def test_alloc_new(): p = Program() q0 = QubitPlaceholder() p.inst(H(q0)) # H 0 q1 = QubitPlaceholder() q2 = QubitPlaceholder() p.inst(CNOT(q1, q2)) # CNOT 1 3 qxxx = QubitPlaceholder() p.inst(H(qxxx)) q3 = QubitPlaceholder() p.inst(X(q3)) # X 4 p = address_qubits(p, { q1: 1, q2: 3, q3: 4, q0: 0, qxxx: 2, }) assert p.out() == "H 0\n" \ "CNOT 1 3\n" \ "H 2\n" \ "X 4\n"
def rus(inputs, w, b): in_reg = list() for i in inputs: in_reg.append(i) an_reg = list() an_reg.append(QubitPlaceholder()) an_reg.append(QubitPlaceholder()) # Gates and classical memory preparation prep_pq = Program() acl_ro = prep_pq.declare('acl_{}_ro'.format(an_reg[0]), 'BIT', 1) # Rotation gates rot_linear_pq = Program() for i in range(len(w)): rot_linear_pq += CRY(w[i])(in_reg[i], an_reg[0]) rot_linear_pq += RY(b, an_reg[0]) rot_pq = Program() rot_pq += rot_linear_pq rot_pq += CY(an_reg[0], an_reg[1]) rot_pq += RZ(-np.pi / 2, an_reg[0]) rot_pq += rot_linear_pq # Ancilla bit measurement pq = Program() pq += prep_pq pq += rot_pq pq += MEASURE(an_reg[0], acl_ro) # Repeated circuit rep_pq = Program() # rep_pq += RESET(reg[1]) rep_pq += RY(-np.pi / 2, an_reg[1]) rep_pq += rot_pq rep_pq += MEASURE(an_reg[0], acl_ro) pq.while_do(acl_ro, rep_pq) return pq, an_reg[1]
def rus_single(input, theta): reg = list() reg.append(input) reg.append(QubitPlaceholder()) reg.append(QubitPlaceholder()) # Gates and classical memory preparation prep_pq = Program() prep_pq += dg_cry prep_pq += dg_cy acl_ro = prep_pq.declare('acl_ro', 'BIT', 1) # Rotation gates rot_pq = Program() rot_pq += CRY(2 * theta)(reg[0], reg[1]) rot_pq += CY(reg[1], reg[2]) rot_pq += RZ(-np.pi / 2, reg[1]) rot_pq += CRY(2 * theta)(reg[0], reg[1]) # Ancilla bit measurement pq = Program() pq += prep_pq pq += rot_pq pq += MEASURE(reg[1], acl_ro) # Repeated circuit rep_pq = Program() # rep_pq += RESET(reg[1]) rep_pq += RY(-np.pi / 2, reg[2]) rep_pq += rot_pq rep_pq += MEASURE(reg[1], acl_ro) pq.while_do(acl_ro, rep_pq) return pq, reg[2]
def period_helper(a, N, size): c1 = QubitPlaceholder() zero = QubitPlaceholder() x = QubitPlaceholder.register(size) b = QubitPlaceholder.register(size + 1) #takes in x and b as zero, finds p = Program() n = 2 * size def_regs = Program() period_regs = def_regs.declare('ro', 'BIT', n) #For one reg, we want H, CUA, R_i m_i, X^m_i for i in range(n - 1, -1, -1): R = Program() R += H(c1) for j in range(i - 1, -1, -1): k = i - j + 1 doit = Program() doit += RK(k)(c1).dagger() R = Program().if_then(period_regs[j], doit, I(c1)) + R R += MEASURE(c1, period_regs[i]) R += Program().if_then(period_regs[i], X(c1), I(c1)) #R = Program(H(c1)) + R R = Program(H(c1)) + UA(c1, x, b, a**(2**i), N, zero) + R p = R + p p = write_in(1, x) + p p = def_regs + p p = get_defs() + p p = address_qubits(p) return p
def test_multi_control(self): """ Tests entanglement with more than one control qubit. NOTE: This will currently fail because pyQuil has a bug with controlled gates and QubitPlaceholder: https://github.com/rigetti/pyquil/issues/905 Once that gets fixed, I'll revisit this function. """ # Construct the program and the qubits - we're going to use 2 separate registers, # where one will be a bunch of control qubits and the other will be a single target # qubit. valid_states = [ "0000", "0010", "0100", "0110", "1000", "1010", "1100", "1111" ] controls = QubitPlaceholder.register(len(valid_states[0]) - 1) target = QubitPlaceholder() program = Program() # Hadamard the first three qubits - these will be the controls for control in controls: program += H(control) # pyQuil supports gates that are controlled by arbitrary many qubits, so # we don't need to mess with Toffoli gates or custom multi-control implementations. # We just have to chain a bunch of controlled() calls for each control qubit. gate = X(target) for control in controls: gate = gate.controlled(control) program += gate # Run the test self.run_test("multi-controlled operation", program, controls + [target], 1000, valid_states)
def test_get_qubits(): q = QubitPlaceholder.register(2) term = PauliTerm("Z", q[0]) * PauliTerm("X", q[1]) assert term.get_qubits() == q q10 = QubitPlaceholder() sum_term = PauliTerm("X", q[0], 0.5) + 0.5j * PauliTerm("Y", q10) * PauliTerm("Y", q[0], 0.5j) assert sum_term.get_qubits() == [q[0], q10]
def run_test(self, description, iterations, buffer): """ Runs the superdense coding algorithm on the given classical buffer. Parameters: description (str): A description of the test, for logging. iterations (int): The number of times to run the program. buffer (list[Bool]): The buffer containing the two bits to send. """ # Construct the registers print(f"Running test: {description}") pair_a = QubitPlaceholder() pair_b = QubitPlaceholder() # Entangle the qubits together self.program += H(pair_a) self.program += CNOT(pair_a, pair_b) # Encode the buffer into the qubits, then decode them into classical measurements self.encode_message(buffer, pair_a) (a_measurement_index, b_measurement_index) = self.decode_message(pair_a, pair_b) # Run the program N times. assigned_program = address_qubits(self.program) assigned_program.wrap_in_numshots_loop(iterations) computer = get_qc(f"2q-qvm", as_qvm=True) executable = computer.compile(assigned_program) results = computer.run(executable) # Check the first qubit to make sure it was always the expected value desired_a_state = int(buffer[0]) for result in results: if result[a_measurement_index] != desired_a_state: self.fail( f"Test {description} failed. The first bit should have been {desired_a_state} " + f"but it was {result[a_measurement_index]}.") else: print( f"The first qubit was {desired_a_state} all {iterations} times." ) # Check the second qubit to make sure it was always the expected value desired_b_state = int(buffer[1]) for result in results: if result[b_measurement_index] != desired_b_state: self.fail( f"Test {description} failed. The first bit should have been {desired_b_state} " + f"but it was {result[b_measurement_index]}.") else: print( f"The second qubit was {desired_b_state} all {iterations} times." ) print("Passed!") print()
def test_reuse_placeholder(): p = Program() q1 = QubitPlaceholder() q2 = QubitPlaceholder() p.inst(H(q1)) p.inst(H(q2)) p.inst(CNOT(q1, q2)) p = address_qubits(p) assert p.out() == "H 0\nH 1\nCNOT 0 1\n"
def test_allocating_qubits_on_multiple_programs(): p = Program() qubit0 = QubitPlaceholder() p.inst(X(qubit0)) q = Program() qubit1 = QubitPlaceholder() q.inst(X(qubit1)) assert address_qubits(p + q).out() == "X 0\nX 1\n"
def test_eq(): p1 = Program() q1 = QubitPlaceholder() q2 = QubitPlaceholder() p1.inst([H(q1), CNOT(q1, q2)]) p1 = address_qubits(p1) p2 = Program() p2.inst([H(0), CNOT(0, 1)]) assert p1 == p2 assert not p1 != p2
def test_placeholders_preserves_modifiers(): cs = QubitPlaceholder.register(3) ts = QubitPlaceholder.register(1) g = X(ts[0]) for c in cs: g = g.controlled(c).dagger() p = Program(g) a = address_qubits(p) assert a[0].modifiers == g.modifiers
def entangle_test(n=5): phi = QubitPlaceholder() p = [QubitPlaceholder() for i in range(n)] test_pqs = [ init_p(p) + entangle(phi, p), init_p(p) + entangle(phi, p) + disentangle(phi, p), init_p(p) + H(phi) + entangle(phi, p), init_p(p) + H(phi) + entangle(phi, p) + disentangle(phi, p), ] wf_sim = WavefunctionSimulator() for pq in test_pqs: print(wf_sim.wavefunction(address_qubits(pq)))
def controlled_modular_multiply(ancilla_cache, program, control, constant, modulus, multiplier): """ This function implements the operation (A*B mod C), where A and C are constants, and B is a qubit register representing a little-endian integer. Remarks: See the Q# source for the "ModularMultiplyByConstantLE" function at https://github.com/Microsoft/QuantumLibraries/blob/master/Canon/src/Arithmetic/Arithmetic.qs """ summand = None if not "summand" in ancilla_cache: summand = QubitPlaceholder.register(len(multiplier)) ancilla_cache["summand"] = summand else: summand = ancilla_cache["summand"] program += controlled_modular_add_product(ancilla_cache, control, constant, modulus, multiplier, summand) for i in range(0, len(multiplier)): program += CSWAP(control, summand[i], multiplier[i]) inverse_mod_value = inverse_mod(constant, modulus) program += controlled_modular_add_product(ancilla_cache, control, inverse_mod_value, modulus, multiplier, summand).dagger()
def simulate_code(kraus_operators, trials, error_code) -> int: """ :param kraus_operators: The set of Kraus operators to apply as the noise model on the identity gate :param trials: The number of times to simulate the program :param error_code: The error code {bit_code, phase_code or shor} to use :return: The number of times the code did not correct back to the logical zero state for "trials" attempts """ # Apply the error_code to some qubits and return back a Program pq pq, code_register = error_code(QubitPlaceholder()) ro = pq.declare('ro', 'BIT', len(code_register)) pq += [MEASURE(qq, rr) for qq, rr in zip(code_register, ro)] # THIS CODE APPLIES THE NOISE FOR YOU kraus_ops = kraus_operators noise_data = Program() for qq in range(3): noise_data.define_noisy_gate("I", [qq], kraus_ops) pq = noise_data + pq # Run the simulation trials times using the QVM and check how many times it did not work results = qvm.run(address_qubits(pq), trials=trials) score = 0 for i in results: count = np.sum(i) #if count >= len(code_register)/2 if count == len(code_register): score += 1 return int(score)
def run_flip_marker_as_phase_marker(program, ancilla_cache, oracle, qubits, oracle_args): """ Runs an oracle, flipping the phase of the input array if the result was |1> instead of flipping the target qubit. Parameters: program (Program): The program being constructed ancilla_cache (dict[string, QubitPlaceholder]): A collection of ancilla qubits that have been allocated in the program for use, paired with a name to help determine when they're free for use. oracle (function): The oracle to run qubits (list[QubitPlaceholder]): The register to run the oracle on oracle_args (anything): An oracle-specific argument object to pass to the oracle during execution """ # Add the phase-flip ancilla qubit to the program if it doesn't already # exist, and set it up in the |-> state phase_marker_target = None if not "phase_marker_target" in ancilla_cache: phase_marker_target = QubitPlaceholder() ancilla_cache["phase_marker_target"] = phase_marker_target program += X(phase_marker_target) program += H(phase_marker_target) else: phase_marker_target = ancilla_cache["phase_marker_target"] # Run the oracle with the phase-flip ancilla as the target - when the # oracle flips this target, it will actually flip the phase of the input # instead of entangling it with the target. if oracle_args is None: oracle(program, qubits, phase_marker_target) else: oracle(program, qubits, phase_marker_target, oracle_args)
def test_exponentiate_3ns(): # testing circuit for 3-terms non-sequential q = QubitPlaceholder.register(8) generator = ( PauliTerm("Y", q[0], 1.0) * PauliTerm("I", q[1], 1.0) * PauliTerm("Y", q[2], 1.0) * PauliTerm("Y", q[3], 1.0) ) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst( [ RX(math.pi / 2.0, q[0]), RX(math.pi / 2.0, q[2]), RX(math.pi / 2.0, q[3]), CNOT(q[0], q[2]), CNOT(q[2], q[3]), RZ(2.0, q[3]), CNOT(q[2], q[3]), CNOT(q[0], q[2]), RX(-math.pi / 2.0, q[0]), RX(-math.pi / 2.0, q[2]), RX(-math.pi / 2.0, q[3]), ] ) assert address_qubits(prog) == address_qubits(result_prog)
def get_rb_gateset(rb_type: str) -> Tuple[List[Gate], Tuple[QubitPlaceholder]]: """ A wrapper around the gateset generation functions. :param rb_type: "1q" or "2q". :returns: list of gates, tuple of qubits """ if rb_type == '1q': q = QubitPlaceholder() return list(oneq_rb_gateset(q)), (q,) if rb_type == '2q': q1, q2 = QubitPlaceholder.register(n=2) return list(twoq_rb_gateset(q1, q2)), (q1, q2) raise ValueError(f"No RB gateset for {rb_type}")
def run_code(error_code, noise, trials=10): """ Takes in an error_code function (e.g. bit_code, phase_code or shor) and runs this code on the QVM""" pq, code_register = error_code(QubitPlaceholder(), noise=noise) ro = pq.declare('ro', 'BIT', len(code_register)) pq += [MEASURE(qq, rr) for qq, rr in zip(code_register, ro)] return qvm.run(address_qubits(pq), trials=trials)
def test_simplify_term_single(): q0, q1, q2 = QubitPlaceholder.register(3) term = ( PauliTerm("Z", q0) * PauliTerm("I", q1) * PauliTerm("X", q2, 0.5j) * PauliTerm("Z", q0, 1.0) ) assert term.id() == "X{}".format(q2) assert term.coefficient == 0.5j
def test_multiple_instantiate(): p = Program() q = QubitPlaceholder() p.inst(H(q)) p = address_qubits(p) assert p.out() == "H 0\n" assert p.out() == "H 0\n"
def correct_errors(self, program, qubits): """ Corrects any errors that have occurred within the logical qubit register. Parameters: program (Program): The program to add the error correction to qubits (list[QubitPlaceholder]): The logical qubit register to check and correct """ parity_qubits = QubitPlaceholder.register(3) parity_measurement = program.declare("parity_measurement", "BIT", 3) # Correct bit flips self.detect_bit_flip_error(program, qubits, parity_qubits, parity_measurement) self.generate_classical_control_corrector(program, qubits, parity_measurement, X) for qubit in parity_qubits: program += RESET(qubit) # Correct phase flips self.detect_phase_flip_error(program, qubits, parity_qubits, parity_measurement) self.generate_classical_control_corrector(program, qubits, parity_measurement, Z)
def test_commuting_sets(): q = QubitPlaceholder.register(8) term1 = PauliTerm("X", q[0]) * PauliTerm("X", q[1]) term2 = PauliTerm("Y", q[0]) * PauliTerm("Y", q[1]) term3 = PauliTerm("Y", q[0]) * PauliTerm("Z", q[2]) pauli_sum = term1 + term2 + term3 commuting_sets(pauli_sum)
def detect_error(self, program, qubits): """ Detects a bit-flip error on one of the three qubits in a logical qubit register. Parameters: program (Program): The program to add the error detection to qubits (list[QubitPlaceholder]): The logical qubit register to check for errors Returns: A MemoryReference list representing the parity measurements. The first one contains the parity of qubits 0 and 1, and the second contains the parity of qubits 0 and 2. """ # The plan here is to check if q0 and q1 have the same parity (00 or 11), and if q0 and q2 # have the same parity. If both checks come out true, then there isn't an error. Otherwise, # if one of the checks reveals a parity discrepancy, we can use the other check to tell us # which qubit is broken. parity_qubits = QubitPlaceholder.register(2) parity_measurement = program.declare("parity_measurement", "BIT", 2) # Check if q0 and q1 have the same value program += CNOT(qubits[0], parity_qubits[0]) program += CNOT(qubits[1], parity_qubits[0]) # Check if q0 and q2 have the same value program += CNOT(qubits[0], parity_qubits[1]) program += CNOT(qubits[2], parity_qubits[1]) # Measure the parity values and return the measurement register program += MEASURE(parity_qubits[0], parity_measurement[0]) program += MEASURE(parity_qubits[1], parity_measurement[1]) return parity_measurement
def test_enumerate(): q0, q1, q5 = QubitPlaceholder.register(3) term = PauliTerm("Z", q0, 1.0) * PauliTerm("Z", q1, 1.0) * PauliTerm( "X", q5, 5) position_op_pairs = [(q0, "Z"), (q1, "Z"), (q5, "X")] for key, val in term: assert (key, val) in position_op_pairs
def test_pauli_sum(): q = QubitPlaceholder.register(8) q_plus = 0.5 * PauliTerm('X', q[0]) + 0.5j * PauliTerm('Y', q[0]) the_sum = q_plus * PauliSum([PauliTerm('X', q[0])]) term_strings = [str(x) for x in the_sum.terms] assert '(0.5+0j)*I' in term_strings assert len(term_strings) == 2 assert len(the_sum.terms) == 2 the_sum = q_plus * PauliTerm('X', q[0]) term_strings = [str(x) for x in the_sum.terms] assert '(0.5+0j)*I' in term_strings assert len(term_strings) == 2 assert len(the_sum.terms) == 2 the_sum = PauliTerm('X', q[0]) * q_plus term_strings = [str(x) for x in the_sum.terms] assert '(0.5+0j)*I' in term_strings assert len(term_strings) == 2 assert len(the_sum.terms) == 2 with pytest.raises(ValueError): _ = PauliSum(sI(q[0])) with pytest.raises(ValueError): _ = PauliSum([1, 1, 1, 1]) with pytest.raises(ValueError): _ = the_sum * []
def test_operations_as_set(): q = QubitPlaceholder.register(6) term_1 = PauliTerm("Z", q[0], 1.0) * PauliTerm("Z", q[1], 1.0) * PauliTerm( "X", q[5], 5) term_2 = PauliTerm("X", q[5], 5) * PauliTerm("Z", q[0], 1.0) * PauliTerm( "Z", q[1], 1.0) assert term_1.operations_as_set() == term_2.operations_as_set()
def test_exponentiate_identity(): q = QubitPlaceholder.register(11) mapping = {qp: Qubit(i) for i, qp in enumerate(q)} generator = PauliTerm("I", q[1], 0.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst() assert address_qubits(prog, mapping) == address_qubits(result_prog, mapping) generator = PauliTerm("I", q[1], 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst( [X(q[0]), PHASE(-1.0, q[0]), X(q[0]), PHASE(-1.0, q[0])]) assert address_qubits(prog, mapping) == address_qubits(result_prog, mapping) generator = PauliTerm("I", q[10], 0.08) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst( [X(q[0]), PHASE(-0.08, q[0]), X(q[0]), PHASE(-0.08, q[0])]) assert address_qubits(prog, mapping) == address_qubits(result_prog, mapping)
def new_logical_qubit(prog: Program, qecc: QECC, name: str) -> CodeBlock: n = qecc.n raw_mem = prog.declare(name, 'BIT', 2 * n) mem = MemoryChunk(raw_mem, 0, raw_mem.declared_size) qubits = [QubitPlaceholder() for _ in range(n)] _initialize_memory(prog, raw_mem, qubits) return CodeBlock(qubits, mem[:n], mem[n:])
def test_check_commutation_rigorous(): # more rigorous test. Get all operators in Pauli group p_n_group = ("I", "X", "Y", "Z") pauli_list = list(product(p_n_group, repeat=3)) pauli_ops = [ list(zip(x, QubitPlaceholder.register(3))) for x in pauli_list ] pauli_ops_pq = [ reduce(mul, (PauliTerm(*x) for x in op)) for op in pauli_ops ] non_commuting_pairs = [] commuting_pairs = [] for x in range(len(pauli_ops_pq)): for y in range(x, len(pauli_ops_pq)): tmp_op = _commutator(pauli_ops_pq[x], pauli_ops_pq[y]) assert len(tmp_op.terms) == 1 if is_zero(tmp_op.terms[0]): commuting_pairs.append((pauli_ops_pq[x], pauli_ops_pq[y])) else: non_commuting_pairs.append((pauli_ops_pq[x], pauli_ops_pq[y])) # now that we have our sets let's check against our code. for t1, t2 in non_commuting_pairs: assert not check_commutation([t1], t2) for t1, t2 in commuting_pairs: assert check_commutation([t1], t2)
def NN_encode(qubit: QubitPlaceholder, N: int) -> (Program, List[QubitPlaceholder]): ### qubit: qubit you want to encode (main qubit) ### N: number of qubits you want to encode the main qubit in. ### For N=1, there is no encoding code_register = QubitPlaceholder.register( N) # the List[QubitPlaceholder] of the qubits you have encoded into code_register[0] = qubit pq = Program() ### creation of GHZ state: for ii in range(N - 1): pq += CNOT(code_register[ii], code_register[ii + 1]) for jj in range(N - 1): pq += H(code_register[jj]) pq += CZ(code_register[jj + 1], code_register[jj]) for kk in range(N - 1): pq += CNOT(code_register[kk], code_register[-1]) return pq, code_register