def test_1_qubit_control(): prog = Program() qubit = Qubit(0) control_qubit = Qubit(1) prog += (ControlledProgramBuilder().with_controls( [control_qubit]).with_target(qubit).with_operation( SIGMA_Z).with_gate_name(SIGMA_Z_NAME).build()) # This should be one "CZ" instruction, from control_qubit to qubit. assert len(prog) == 1 instruction = prog.instructions[0] assert instruction.name == (ControlledProgramBuilder().format_gate_name( "C", SIGMA_Z_NAME)) assert instruction.qubits == [control_qubit, qubit]
def double_control_test(instructions, target_qubit, control_qubit_one, control_qubit_two): """A list of asserts testing the simple case of a double controlled Z gate. Used in the next two tests.""" cpg = ControlledProgramBuilder() sqrt_z = cpg.format_gate_name("SQRT", SIGMA_Z_NAME) assert instructions[0][1].operator_name == (cpg.format_gate_name( "C", sqrt_z)) assert instructions[0][1].arguments == [control_qubit_two, target_qubit] assert instructions[1][1].operator_name == cpg.format_gate_name("C", "NOT") assert instructions[1][1].arguments == [ control_qubit_one, control_qubit_two ] assert instructions[2][1].operator_name == cpg.format_gate_name( "C", sqrt_z) + '-INV' assert instructions[2][1].arguments == [control_qubit_two, target_qubit] assert instructions[3][1].operator_name == cpg.format_gate_name("C", "NOT") assert instructions[3][1].arguments == [ control_qubit_one, control_qubit_two ] assert instructions[4][1].operator_name == cpg.format_gate_name( "C", sqrt_z) assert instructions[4][1].arguments == [control_qubit_one, target_qubit]
def test_1_qubit_control(): prog = Program() qubit = prog.alloc() control_qubit = prog.alloc() prog += (ControlledProgramBuilder().with_controls( [control_qubit]).with_target(qubit).with_operation( SIGMA_Z).with_gate_name(SIGMA_Z_NAME).build()) # This should be one "CZ" instruction, from control_qubit to qubit. assert prog_len(prog) == 1 prog.synthesize() instruction = non_action_insts(prog)[0] assert instruction[1].operator_name == ( ControlledProgramBuilder().format_gate_name("C", SIGMA_Z_NAME)) assert instruction[1].arguments == [control_qubit, qubit]
def decomposed_diffusion_program(qubits): """ Constructs the diffusion operator used in Grover's Algorithm, acted on both sides by an a Hadamard gate on each qubit. Note that this means that the matrix representation of this operator is diag(1, -1, ..., -1). In particular, this decomposes the diffusion operator, which is a :math:`2**{len(qubits)}\times2**{len(qubits)}` sparse matrix, into :math:`\mathcal{O}(len(qubits)**2) single and two qubit gates. See C. Lavor, L.R.U. Manssur, and R. Portugal (2003) `Grover's Algorithm: Quantum Database Search`_ for more information. .. _`Grover's Algorithm: Quantum Database Search`: https://arxiv.org/abs/quant-ph/0301079 :param qubits: A list of ints corresponding to the qubits to operate on. The operator operates on bistrings of the form ``|qubits[0], ..., qubits[-1]>``. """ program = pq.Program() if len(qubits) == 1: program.inst(Z(qubits[0])) else: program.inst([X(q) for q in qubits]) program.inst(H(qubits[-1])) program.inst(RZ(-np.pi, qubits[0])) program += (ControlledProgramBuilder().with_controls( qubits[:-1]).with_target(qubits[-1]).with_operation( X_GATE).with_gate_name(X_GATE_LABEL).build()) program.inst(RZ(-np.pi, qubits[0])) program.inst(H(qubits[-1])) program.inst([X(q) for q in qubits]) return program
def diffusion_program(qubits): """Constructs the diffusion operator used in Grover's Algorithm, acted on both sides by an a Hadamard gate on each qubit. Note that this means that the matrix representation of this operator is diag(1, -1, ..., -1). See C. Lavor, L.R.U. Manssur, and R. Portugal (2003) `Grover's Algorithm: Quantum Database Search`_ for more information. .. _`Grover's Algorithm: Quantum Database Search`: https://arxiv.org/abs/quant-ph/0301079 :param qubits: A list of ints corresponding to the qubits to operate on. The operator operates on bistrings of the form |qubits[0], ..., qubits[-1]>. """ diffusion_program = pq.Program() if len(qubits) == 1: diffusion_program.inst(Z(qubits[0])) else: diffusion_program.inst([X(q) for q in qubits]) diffusion_program.inst(H(qubits[-1])) diffusion_program.inst(RZ(-np.pi)(qubits[0])) diffusion_program += (ControlledProgramBuilder() .with_controls(qubits[:-1]) .with_target(qubits[-1]) .with_operation(X_GATE) .with_gate_name("NOT").build()) diffusion_program.inst(RZ(-np.pi)(qubits[0])) diffusion_program.inst(H(qubits[-1])) diffusion_program.inst([X(q) for q in qubits]) return diffusion_program
def test_recursive_builder(): """Here we test the _recursive_builder in ControlledProgramBuilder individually.""" control_qubit_one = 1 control_qubit_two = 2 target_qubit = 3 cpg = (ControlledProgramBuilder().with_controls( [control_qubit_one, control_qubit_two]).with_target( target_qubit).with_operation(SIGMA_Z).with_gate_name(SIGMA_Z_NAME)) prog = cpg._recursive_builder(cpg.operation, cpg.gate_name, cpg.control_qubits, cpg.target_qubit) # Run tests double_control_test(prog.instructions, Qubit(target_qubit), Qubit(control_qubit_one), Qubit(control_qubit_two))
def test_2_qubit_control(): """Test that ControlledProgramBuilder builds the program correctly all the way through.""" prog = Program() qubit = Qubit(0) control_qubit_one = Qubit(1) control_qubit_two = Qubit(2) prog += (ControlledProgramBuilder() .with_controls([control_qubit_one, control_qubit_two]) .with_target(qubit) .with_operation(SIGMA_Z) .with_gate_name(SIGMA_Z_NAME).build()) # This should be one "CZ" instruction, from control_qubit to qubit. assert len(prog) == 5 # Run tests double_control_test(prog.instructions, qubit, control_qubit_one, control_qubit_two)
def test_2_qubit_control(): """Test that ControlledProgramBuilder builds the program correctly all the way through.""" prog = Program() qubit = prog.alloc() control_qubit_one = prog.alloc() control_qubit_two = prog.alloc() prog += (ControlledProgramBuilder().with_controls([ control_qubit_one, control_qubit_two ]).with_target(qubit).with_operation(SIGMA_Z).with_gate_name("Z").build()) # This should be one "CZ" instruction, from control_qubit to qubit. assert prog_len(prog) == 5 prog.synthesize() instructions = non_action_insts(prog) # Run tests double_control_test(instructions, qubit, control_qubit_one, control_qubit_two)
def basis_selector_oracle(qubits: List[int], bitstring: str) -> Program: """ Defines an oracle that selects the ith element of the computational basis. Flips the sign of the state :math:`\\vert x\\rangle>` if and only if x==bitstring and does nothing otherwise. :param qubits: The qubits the oracle is called on. The qubits are assumed to be ordered from most significant qubit to least significant qubit. :param bitstring: The desired bitstring, given as a string of ones and zeros. e.g. "101" :return: A program representing this oracle. """ if len(qubits) != len(bitstring): raise ValueError("The bitstring should be the same length as the number of qubits.") oracle_prog = Program() # In the case of one qubit, we just want to flip the phase of state relative to the other. if len(bitstring) == 1: oracle_prog.inst(Z(qubits[0])) return oracle_prog else: bitflip_prog = Program() for i, qubit in enumerate(qubits): if bitstring[i] == '0': bitflip_prog.inst(X(qubit)) oracle_prog += bitflip_prog controls = qubits[:-1] target = qubits[-1] operation = np.array([[1, 0], [0, -1]]) gate_name = 'Z' n_qubit_controlled_z = (ControlledProgramBuilder() .with_controls(controls) .with_target(target) .with_operation(operation) .with_gate_name(gate_name) .build()) oracle_prog += n_qubit_controlled_z oracle_prog += bitflip_prog return oracle_prog