Example #1
0
def _generate_experiment_programs(
        tomo_experiment: TomographyExperiment,
        active_reset: bool = False) -> Tuple[List[Program], List[List[int]]]:
    """
    Generate the programs necessary to estimate the observables in a TomographyExperiment.
    Grouping of settings to be run in parallel, e.g. by a call to group_experiments, should be
    done before this function is called.

    .. CAUTION::
        One must be careful with compilation of the output programs before the appropriate MEASURE
        instructions are added, because compilation may re-index the qubits so that
        the output list of `measure_qubits` no longer accurately indexes the qubits that
        should be measured.

    :param tomo_experiment: a single TomographyExperiment to be translated to a series of programs
        that, when run serially, can be used to estimate each of its observables.
    :param active_reset: whether or not to begin the program by actively resetting. If true,
        execution of each of the returned programs in a loop on the QPU will generally be faster.
    :return: a list of programs along with a corresponding list of the groups of qubits that are
        measured by that program. The returned programs may be run on a qc after measurement
        instructions are added for the corresponding group of qubits in meas_qubits, or by a call
        to `qc.run_symmetrized_readout` -- see :func:`raw_estimate_observables` for possible usage.
    """
    # Outer loop over a collection of grouped settings for which we can simultaneously estimate.
    programs = []
    meas_qubits = []
    for settings in tomo_experiment:

        # Prepare a state according to the amalgam of all setting.in_state
        total_prog = Program()
        if active_reset:
            total_prog += RESET()
        max_weight_in_state = _max_weight_state(setting.in_state
                                                for setting in settings)
        if max_weight_in_state is None:
            raise ValueError(
                "Input states are not compatible. Re-group the experiment settings "
                "so that groups of parallel settings have compatible input states."
            )
        for oneq_state in max_weight_in_state.states:
            total_prog += _one_q_state_prep(oneq_state)

        # Add in the program
        total_prog += tomo_experiment.program

        # Prepare for measurement state according to setting.out_operator
        max_weight_out_op = _max_weight_operator(setting.out_operator
                                                 for setting in settings)
        if max_weight_out_op is None:
            raise ValueError(
                "Observables not compatible. Re-group the experiment settings "
                "so that groups of parallel settings have compatible observables."
            )
        for qubit, op_str in max_weight_out_op:
            total_prog += _local_pauli_eig_meas(op_str, qubit)

        programs.append(total_prog)

        meas_qubits.append(max_weight_out_op.get_qubits())
    return programs, meas_qubits
Example #2
0
def test_qc_joint_expectation(forest):
    device = NxDevice(nx.complete_graph(2))
    qc = QuantumComputer(
        name="testy!", qam=QVM(connection=forest), device=device, compiler=DummyCompiler()
    )

    # |01> state program
    p = Program()
    p += RESET()
    p += X(0)
    p.wrap_in_numshots_loop(10)

    # ZZ experiment
    sz = ExperimentSetting(
        in_state=sZ(0) * sZ(1), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]]
    )
    e = Experiment(settings=[sz], program=p)

    results = qc.experiment(e)

    # ZZ expectation value for state |01> is -1
    assert np.isclose(results[0].expectation, -1)
    assert np.isclose(results[0].std_err, 0)
    assert results[0].total_counts == 40
    # Z0 expectation value for state |01> is -1
    assert np.isclose(results[0].additional_results[0].expectation, -1)
    assert results[0].additional_results[1].total_counts == 40
    # Z1 expectation value for state |01> is 1
    assert np.isclose(results[0].additional_results[1].expectation, 1)
    assert results[0].additional_results[1].total_counts == 40
Example #3
0
def test_validate_supported_quil_reset_qubit():
    prog = Program(
        RESET(2),
    )
    with pytest.raises(ValueError):
        validate_supported_quil(prog)
    assert not prog.is_supported_on_qpu()
Example #4
0
def test_validate_protoquil_reset_qubit():
    prog = Program(
        RESET(2),
    )
    with pytest.raises(ValueError):
        validate_protoquil(prog)
    assert not prog.is_protoquil()
def initialize_toric_code(primal: nx.Graph, dual: nx.Graph, distance: nx.Graph, L: int, trials=100) -> Program: 
    """ Initializes the toric code into an appropriate eigenstate of the stabilizers, assuming 
    the qubits begin in the state |0> \tensor |0> \tensor ... \tensor |0> before initialization. 

    :param primal, dual, distance: primal/dual/distance graphs returned by construct_toric_code 
    :param L: number of physical qubits on one side of the lattice 
    :param trials: number of trials to obtain an even number of qubit errors 
    :returns: program representing correction operation 
    """
    # A hacky way to ensure the initialization works: 
    # run the syndrome extraction until we return an even 
    # number of errors (okay for small graphs)
    for t in range(trials):
        # Set up programs, and reset qubits if needed 
        primal_initial = Program() + RESET()
        # Perform syndrome extraction on primal graph 
        primal_faulty_nodes = syndrome_extraction(primal, L, primal_initial, "X")
        test = (len(primal_faulty_nodes) % 2 == 0) 
        if test: 
            break
        
    assert test, "Failed to find even number of faulty nodes for primal and dual graphs"
    # With an even number of faulty nodes, we can now run the mwpm algorithm 
    # and correct the -1 eigenvalues 
    primal_correction_paths = mwpm(primal, distance, L, primal_faulty_nodes)
    
    # Construct pyquil program to carry out corrections 
    primal_correct_pq = apply_operation(primal_correction_paths, primal, Z)
    return primal_correct_pq
def test_qc_joint_expectation(client_configuration: QCSClientConfiguration,
                              dummy_compiler: DummyCompiler):
    qc = QuantumComputer(name="testy!",
                         qam=QVM(client_configuration=client_configuration),
                         compiler=dummy_compiler)

    # |01> state program
    p = Program()
    p += RESET()
    p += X(0)
    p.wrap_in_numshots_loop(10)

    # ZZ experiment
    sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)),
                           out_operator=sZ(0) * sZ(1),
                           additional_expectations=[[0], [1]])
    e = Experiment(settings=[sz], program=p)

    results = qc.run_experiment(e)

    # ZZ expectation value for state |01> is -1
    assert np.isclose(results[0].expectation, -1)
    assert np.isclose(results[0].std_err, 0)
    assert results[0].total_counts == 40
    # Z0 expectation value for state |01> is -1
    assert np.isclose(results[0].additional_results[0].expectation, -1)
    assert results[0].additional_results[1].total_counts == 40
    # Z1 expectation value for state |01> is 1
    assert np.isclose(results[0].additional_results[1].expectation, 1)
    assert results[0].additional_results[1].total_counts == 40
Example #7
0
def test_qc_expectation_on_qvm(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler):
    # regression test for https://github.com/rigetti/forest-tutorials/issues/2
    qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler)

    p = Program()
    theta = p.declare("theta", "REAL")
    p += RESET()
    p += RY(theta, 0)
    p.wrap_in_numshots_loop(10000)

    sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0)), out_operator=sX(0))
    e = Experiment(settings=[sx], program=p)

    thetas = [-np.pi / 2, 0.0, np.pi / 2]
    results = []

    # Verify that multiple calls to qc.experiment with the same experiment backed by a QVM that
    # requires_exectutable does not raise an exception.
    for theta in thetas:
        results.append(qc.experiment(e, memory_map={"theta": [theta]}))

    assert np.isclose(results[0][0].expectation, -1.0, atol=0.01)
    assert np.isclose(results[0][0].std_err, 0)
    assert results[0][0].total_counts == 20000

    # bounds on atol and std_err here are a little loose to try and avoid test flakiness.
    assert np.isclose(results[1][0].expectation, 0.0, atol=0.1)
    assert results[1][0].std_err < 0.01
    assert results[1][0].total_counts == 20000

    assert np.isclose(results[2][0].expectation, 1.0, atol=0.01)
    assert np.isclose(results[2][0].std_err, 0)
    assert results[2][0].total_counts == 20000
Example #8
0
def test_qc_expectation(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler):
    qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler)

    # bell state program
    p = Program()
    p += RESET()
    p += H(0)
    p += CNOT(0, 1)
    p.wrap_in_numshots_loop(10)

    # XX, YY, ZZ experiment
    sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sX(0) * sX(1))
    sy = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sY(0) * sY(1))
    sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1))

    e = Experiment(settings=[sx, sy, sz], program=p)

    results = qc.experiment(e)

    # XX expectation value for bell state |00> + |11> is 1
    assert np.isclose(results[0].expectation, 1)
    assert np.isclose(results[0].std_err, 0)
    assert results[0].total_counts == 40

    # YY expectation value for bell state |00> + |11> is -1
    assert np.isclose(results[1].expectation, -1)
    assert np.isclose(results[1].std_err, 0)
    assert results[1].total_counts == 40

    # ZZ expectation value for bell state |00> + |11> is 1
    assert np.isclose(results[2].expectation, 1)
    assert np.isclose(results[2].std_err, 0)
    assert results[2].total_counts == 40
def test_qc_joint_calibration(client_configuration: QCSClientConfiguration):
    # noise model with 95% symmetrized readout fidelity per qubit
    noise_model = asymmetric_ro_model([0, 1], 0.945, 0.955)
    qc = get_qc("2q-qvm", client_configuration=client_configuration)
    qc.qam.noise_model = noise_model

    # |01> state program
    p = Program()
    p += RESET()
    p += X(0)
    p.wrap_in_numshots_loop(10000)

    # ZZ experiment
    sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)),
                           out_operator=sZ(0) * sZ(1),
                           additional_expectations=[[0], [1]])
    e = Experiment(settings=[sz], program=p)

    results = qc.run_experiment(e)

    # ZZ expectation value for state |01> with 95% RO fid on both qubits is about -0.81
    assert np.isclose(results[0].expectation, -0.81, atol=0.01)
    assert results[0].total_counts == 40000
    # Z0 expectation value for state |01> with 95% RO fid on both qubits is about -0.9
    assert np.isclose(results[0].additional_results[0].expectation,
                      -0.9,
                      atol=0.01)
    assert results[0].additional_results[1].total_counts == 40000
    # Z1 expectation value for state |01> with 95% RO fid on both qubits is about 0.9
    assert np.isclose(results[0].additional_results[1].expectation,
                      0.9,
                      atol=0.01)
    assert results[0].additional_results[1].total_counts == 40000
Example #10
0
    def _run_program(self, program):
        program = program.copy()

        if self.qpu:
            # time to go through the compiler. whee!
            pragma = Program(
                [Pragma("INITIAL_REWIRING", ['"PARTIAL"']),
                 RESET()])
            program = pragma + program
            program = self._wrap_program(program)
            nq_program = self._qc.compiler.quil_to_native_quil(program)
            gate_count = sum(1 for instr in nq_program
                             if isinstance(instr, Gate))
            executable = self._qc.compiler.native_quil_to_executable(
                nq_program)
            results = self._qc.run(executable=executable)
        else:
            program = self._wrap_program(program)
            gate_count = len(program)
            results = self._qc.run(program)

        info = {
            "gate_count": gate_count
        }  # compiled length for qpu, uncompiled for qvm
        return results, info
def get_calibration_program(observable: PauliTerm, noisy_program: Program = None,
                            active_reset: bool = False) -> Program:
    """
    Program required for calibrating the given observable.

    :param observable: observable to calibrate
    :param noisy_program: a program with readout and gate noise defined; only useful for QVM
    :param active_reset: whether or not to begin the program by actively resetting. If true,
        execution of each of the returned programs in a loop on the QPU will generally be faster.
    :return: Program performing the calibration
    """
    calibr_prog = Program()

    if active_reset:
        calibr_prog += RESET()

    # Inherit any noisy attributes from noisy_program, including gate definitions
    # and applications which can be handy in simulating noisy channels
    if noisy_program is not None:
        # Inherit readout error instructions from main Program
        readout_povm_instruction = [i for i in noisy_program.out().split('\n')
                                    if 'PRAGMA READOUT-POVM' in i]
        calibr_prog += readout_povm_instruction
        # Inherit any definitions of noisy gates from main Program
        kraus_instructions = [i for i in noisy_program.out().split('\n') if 'PRAGMA ADD-KRAUS' in i]
        calibr_prog += kraus_instructions

    # Prepare the +1 eigenstate for the out operator
    for q, op in observable.operations_as_set():
        calibr_prog += _one_q_pauli_prep(label=op, index=0, qubit=q)
    # Measure the out operator in this state
    for q, op in observable.operations_as_set():
        calibr_prog += _local_pauli_eig_meas(op, q)

    return calibr_prog
Example #12
0
def test_validate_protoquil_reset_first():
    prog = Program(
        H(0),
        RESET(),
    )
    with pytest.raises(ValueError):
        validate_protoquil(prog)
    assert not prog.is_protoquil()
Example #13
0
def test_validate_protoquil_with_pragma():
    prog = Program(
        RESET(),
        H(1),
        Pragma('DELAY'),
        MEASURE(1)
    )
    assert prog.is_protoquil()
Example #14
0
def test_validate_supported_quil_with_pragma():
    prog = Program(
        RESET(),
        H(1),
        Pragma('DELAY'),
        MEASURE(1, None)
    )
    assert prog.is_supported_on_qpu()
    def generate_rigetti(self):
        import pyquil
        from pyquil.quil import Program
        from pyquil.gates import H, RZ, RX, RY, CNOT, MEASURE, RESET
        from pyquil.api import get_qc
        self.rigetti_circuits_list=[]
        print("Creating Pyquil program list...")
        self.logfile.write("Creating Pyquil program list...")
        for circuit in self.circuits_list:
            p = pyquil.Program(RESET()) #compressed program
            ro = p.declare('ro', memory_type='BIT', memory_size=self.num_qubits)
            for gate in circuit.gates:
                if gate.name in "H":
                    p.inst(pyquil.gates.H(gate.qubits[0]))
                elif gate.name in "RZ":
                    p.inst(pyquil.gates.RZ(gate.angles[0],gate.qubits[0]))
                elif gate.name in "RX":
                    p.inst(pyquil.gates.RX(gate.angles[0],gate.qubits[0]))
                elif gate.name in "CNOT":
                    p.inst(pyquil.gates.CNOT(gate.qubits[0],gate.qubits[1]))
            for i in range(self.num_qubits):
                p.inst(pyquil.gates.MEASURE(i,ro[i]))
            p.wrap_in_numshots_loop(self.shots)
            self.rigetti_circuits_list.append(p)

        if "y" in self.compile:
            qc=get_qc(self.device_choice)
            if self.JZ != 0 and self.JX==self.JY==0 and self.h_ext!=0 and self.ext_dir=="X" and self.auto_ds_compile=="y":
                #TFIM
                print("TFIM detected, enabling DS compiler")
                self.logfile.write("TFIM detected, enabling DS compiler")
                temp=[]
                for circuit in self.rigetti_circuits_list:
                    temp.append(ds_compile(circuit,self.backend,self.shots))
                self.rigetti_circuits_list=temp

            elif self.default_compiler in "ds":
                temp=[]
                print("Compiling circuits...")
                self.logfile.write("Compiling circuits...")
                for circuit in self.rigetti_circuits_list:
                    temp.append(ds_compile(circuit,self.backend,self.shots))
                self.rigetti_circuits_list=temp
                print("Circuits compiled successfully")
                self.logfile.write("Circuits compiled successfully")
            elif self.default_compiler in "native":
                temp=[]
                print("Transpiling circuits...")
                self.logfile.write("Transpiling circuits...")
                for circuit in self.rigetti_circuits_list:
                    circ = qc.compile(circuit)
                    temp.append(circ)
                self.rigetti_circuits_list=temp
                print("Circuits transpiled successfully")
                self.logfile.write("Circuits transpiled successfully")

        print("Pyquil program list created successfully")
        self.logfile.write("Pyquil program list created successfully")
Example #16
0
    def pre_expval(self):
        """Run the QVM"""
        # pylint: disable=attribute-defined-outside-init
        for e in self.expval_queue:
            wire = [e.wires[0]]

            if e.name == 'PauliX':
                # X = H.Z.H
                self.apply('Hadamard', wire, [])

            elif e.name == 'PauliY':
                # Y = (HS^)^.Z.(HS^) and S^=SZ
                self.apply('PauliZ', wire, [])
                self.apply('S', wire, [])
                self.apply('Hadamard', wire, [])

            elif e.name == 'Hadamard':
                # H = Ry(-pi/4)^.Z.Ry(-pi/4)
                self.apply('RY', wire, [-np.pi/4])

            elif e.name == 'Hermitian':
                # For arbitrary Hermitian matrix H, let U be the unitary matrix
                # that diagonalises it, and w_i be the eigenvalues.
                H = e.parameters[0]
                Hkey = tuple(H.flatten().tolist())

                if Hkey in self._eigs:
                    # retrieve eigenvectors
                    U = self._eigs[Hkey]['eigvec']
                else:
                    # store the eigenvalues corresponding to H
                    # in a dictionary, so that they do not need to
                    # be calculated later
                    w, U = np.linalg.eigh(H)
                    self._eigs[Hkey] = {'eigval': w, 'eigvec': U}

                # Perform a change of basis before measuring by applying U^ to the circuit
                self.apply('QubitUnitary', wire, [U.conj().T])

        prag = Program(Pragma('INITIAL_REWIRING', ['"PARTIAL"']))

        if self.active_reset:
            prag += RESET()

        self.prog = prag + self.prog

        qubits = list(self.prog.get_qubits())
        ro = self.prog.declare('ro', 'BIT', len(qubits))
        for i, q in enumerate(qubits):
            self.prog.inst(MEASURE(q, ro[i]))

        self.prog.wrap_in_numshots_loop(self.shots)
        executable = self.qc.compile(self.prog)

        bitstring_array = self.qc.run(executable=executable)
        self.state = {}
        for i, q in enumerate(qubits):
            self.state[q] = bitstring_array[:, i]
Example #17
0
def test_validate_supported_quil_multiple_measures():
    prog = Program(
        RESET(),
        H(1),
        Pragma('DELAY'),
        MEASURE(1, None),
        MEASURE(1, None)
    )
    with pytest.raises(ValueError):
        validate_supported_quil(prog)
Example #18
0
    def reset(self, qubit_index: Optional[int] = None) -> "Program":
        """
        Reset all qubits or just a specific qubit at qubit_index.

        :param qubit_index: The address of the qubit to reset.
            If None, reset all qubits.
        :returns: The Quil Program with the appropriate reset instruction appended, e.g.
                  RESET 0
        """
        return self.inst(RESET(qubit_index))
Example #19
0
    def pre_measure(self):
        """Run the QVM"""
        # pylint: disable=attribute-defined-outside-init
        for e in self.obs_queue:
            wires = e.wires

            if e.name in [
                    "PauliX", "PauliY", "PauliZ", "Identity", "Hadamard"
            ]:
                self.pre_rotations(e.name, wires)

            elif e.name == "Hermitian":
                # For arbitrary Hermitian matrix H, let U be the unitary matrix
                # that diagonalises it, and w_i be the eigenvalues.
                H = e.parameters[0]
                Hkey = tuple(H.flatten().tolist())

                if Hkey in self._eigs:
                    # retrieve eigenvectors
                    U = self._eigs[Hkey]["eigvec"]
                else:
                    # store the eigenvalues corresponding to H
                    # in a dictionary, so that they do not need to
                    # be calculated later
                    w, U = np.linalg.eigh(H)
                    self._eigs[Hkey] = {"eigval": w, "eigvec": U}

                # Perform a change of basis before measuring by applying U^ to the circuit
                self.apply("QubitUnitary", wires, [U.conj().T])

        prag = Program(Pragma("INITIAL_REWIRING", ['"PARTIAL"']))

        if self.active_reset:
            prag += RESET()

        self.prog = prag + self.prog

        qubits = sorted(self.prog.get_qubits())
        ro = self.prog.declare("ro", "BIT", len(qubits))
        for i, q in enumerate(qubits):
            self.prog.inst(MEASURE(q, ro[i]))

        self.prog.wrap_in_numshots_loop(self.shots)

        if "pyqvm" in self.qc.name:
            bitstring_array = self.qc.run(self.prog)
        else:
            self.compiled = self.qc.compile(self.prog)
            bitstring_array = self.qc.run(executable=self.compiled)

        self.state = {}
        for i, q in enumerate(qubits):
            self.state[q] = bitstring_array[:, i]
Example #20
0
def test_biased_coin():
    # sample from a 75% heads and 25% tails coin
    prog = (
        Program().inst(Declare("ro", "BIT"), RX(np.pi / 3, 0)).measure(0, MemoryReference("ro", 0))
    )

    results = []
    qam = PyQVM(n_qubits=1, quantum_simulator_type=ReferenceWavefunctionSimulator)
    for _ in range(1000):
        qam.execute(prog)
        results += [qam.ram["ro"][0]]
        qam.execute(Program(RESET()))

    coin_bias = sum(results) / 1000
    assert np.isclose(coin_bias, 0.25, atol=0.05, rtol=0.05)
Example #21
0
    def run(q_comp, program, n_shots):
        start = time.time()

        if use_active_reset:
            reset_measure_program = Program(RESET())
            program = reset_measure_program + program

        # run the program num_shots many times
        program.wrap_in_numshots_loop(n_shots)
        executable = q_comp.compiler.native_quil_to_executable(program)

        res = q_comp.run(executable)

        end = time.time()
        return res, end - start
Example #22
0
def test_reset():
    p = Program()
    p.reset(0)
    p.reset()
    assert p.out() == "RESET 0\nRESET\n"

    program = Program()
    qubit = QubitPlaceholder()
    # address_qubits() won't work unless there's a gate besides
    # RESET on a QubitPlaceholder, this is just here to make
    # addressing work
    program += X(qubit)

    program += RESET(qubit)
    program = address_qubits(program)
    assert program.out() == "X 0\nRESET 0\n"
Example #23
0
    def generate_calibration_experiment(self) -> "Experiment":
        """
        Generate another ``Experiment`` object that can be used to calibrate the various multi-qubit
        observables involved in this ``Experiment``. This is achieved by preparing the plus-one
        (minus-one) eigenstate of each ``out_operator``, and measuring the resulting expectation
        value of the same ``out_operator``. Ideally, this would always give +1 (-1), but when
        symmetric readout error is present the effect is to scale the resultant expectations by some
        constant factor. Determining this scale factor is what we call *readout calibration*, and
        then the readout error in subsequent measurements can then be mitigated by simply dividing
        by the scale factor.

        :return: A new ``Experiment`` that can calibrate the readout error of all the
            observables involved in this experiment.
        """
        if self.calibration != CalibrationMethod.PLUS_EIGENSTATE:
            raise ValueError(
                'We currently only support the "plus eigenstate" calibration method.'
            )

        calibration_settings = []
        for settings in self:
            assert len(settings) == 1
            calibration_settings.append(
                ExperimentSetting(
                    in_state=settings[0].out_operator,
                    out_operator=settings[0].out_operator,
                    additional_expectations=settings[0].
                    additional_expectations,
                ))

        calibration_program = Program()
        if self.reset:
            calibration_program += RESET()
        calibration_program.wrap_in_numshots_loop(self.shots)

        if self.symmetrization != SymmetrizationLevel.EXHAUSTIVE:
            raise ValueError(
                "We currently only support calibration for exhaustive symmetrization"
            )

        return Experiment(
            settings=calibration_settings,
            program=calibration_program,
            symmetrization=SymmetrizationLevel.EXHAUSTIVE,
            calibration=CalibrationMethod.NONE,
        )
Example #24
0
def test_unsupported_ops():
    target = Label("target")
    base_prog = Program(Declare('reg1', 'BIT'), Declare('reg2', 'BIT'), H(0),
                        JumpTarget(target), CNOT(0, 1))

    bad_ops = [
        RESET(0), WAIT,
        Jump(target),
        MOVE(MemoryReference('reg1'), MemoryReference('reg2'))
    ]

    assert to_latex(base_prog)

    for op in bad_ops:
        prog = base_prog + op
        with pytest.raises(ValueError):
            _ = to_latex(prog)
Example #25
0
def two_POVM(theta0, phi0, theta1, theta2) -> Program:

    # for the purpose of POVM we choose the most connected qubit (10 in the case) to be the measured one
    ancilla = [2]
    target = 1

    program = Program(RESET())
    # create initial state
    if theta0 != 0:
        program.inst(RY(theta0, target))
    if phi0 != 0:
        program.inst(RZ(phi0, target))

    # 1st AP module
    program.inst(POVM_module_1(theta1, theta2, ancilla, target))

    return program
Example #26
0
def test_is_protoquil():
    prog = Program(Declare('ro', 'BIT'), MEASURE(1, MemoryReference("ro", 0)),
                   H(1), RESET())
    validate_protoquil(prog)
    assert prog.is_protoquil()

    prog = Program(Declare('ro', 'BIT'), H(0), Y(1), CNOT(0, 1)) \
        .measure(0, MemoryReference("ro", 0)) \
        .if_then(MemoryReference("ro", 0), Program(X(0)), Program())
    with pytest.raises(ValueError):
        validate_protoquil(prog)
    assert not prog.is_protoquil()

    prog = Program(Declare('ro', 'BIT'), ClassicalNot(MemoryReference("ro",
                                                                      0)))
    with pytest.raises(ValueError):
        validate_protoquil(prog)
    assert not prog.is_protoquil()
Example #27
0
    def apply(self, operations, **kwargs):
        """Run the QVM"""
        # pylint: disable=attribute-defined-outside-init
        super().apply(operations, **kwargs)

        prag = Program(Pragma("INITIAL_REWIRING", ['"PARTIAL"']))

        if self.active_reset:
            prag += RESET()

        self.prog = prag + self.prog

        qubits = sorted(self.wiring.values())
        ro = self.prog.declare("ro", "BIT", len(qubits))
        for i, q in enumerate(qubits):
            self.prog.inst(MEASURE(q, ro[i]))

        self.prog.wrap_in_numshots_loop(self.shots)
Example #28
0
def test_qc_expectation_larger_lattice(forest):
    device = NxDevice(nx.complete_graph(4))
    qc = QuantumComputer(name='testy!',
                         qam=QVM(connection=forest),
                         device=device,
                         compiler=DummyCompiler())

    q0 = 2
    q1 = 3

    # bell state program
    p = Program()
    p += RESET()
    p += H(q0)
    p += CNOT(q0, q1)
    p.wrap_in_numshots_loop(10)

    # XX, YY, ZZ experiment
    sx = ExperimentSetting(in_state=sZ(q0) * sZ(q1),
                           out_operator=sX(q0) * sX(q1))
    sy = ExperimentSetting(in_state=sZ(q0) * sZ(q1),
                           out_operator=sY(q0) * sY(q1))
    sz = ExperimentSetting(in_state=sZ(q0) * sZ(q1),
                           out_operator=sZ(q0) * sZ(q1))

    e = TomographyExperiment(settings=[sx, sy, sz], program=p)

    results = qc.experiment(e)

    # XX expectation value for bell state |00> + |11> is 1
    assert np.isclose(results[0].expectation, 1)
    assert np.isclose(results[0].std_err, 0)
    assert results[0].total_counts == 40

    # YY expectation value for bell state |00> + |11> is -1
    assert np.isclose(results[1].expectation, -1)
    assert np.isclose(results[1].std_err, 0)
    assert results[1].total_counts == 40

    # ZZ expectation value for bell state |00> + |11> is 1
    assert np.isclose(results[2].expectation, 1)
    assert np.isclose(results[2].std_err, 0)
    assert results[2].total_counts == 40
Example #29
0
def test_qc_calibration_2q(client_configuration: QCSClientConfiguration):
    # noise model with 95% symmetrized readout fidelity per qubit
    noise_model = asymmetric_ro_model([0, 1], 0.945, 0.955)
    qc = get_qc("2q-qvm", client_configuration=client_configuration)
    qc.qam.noise_model = noise_model

    # bell state program (doesn't matter)
    p = Program()
    p += RESET()
    p += H(0)
    p += CNOT(0, 1)
    p.wrap_in_numshots_loop(10000)

    # ZZ experiment
    sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1))
    e = Experiment(settings=[sz], program=p)

    results = qc.calibrate(e)

    # ZZ expectation should just be (1 - 2 * readout_error_q0) * (1 - 2 * readout_error_q1)
    np.isclose(results[0].expectation, 0.81, atol=0.01)
    assert results[0].total_counts == 40000
Example #30
0
def test_qc_calibration_1q(forest):
    # noise model with 95% symmetrized readout fidelity per qubit
    noise_model = asymmetric_ro_model([0], 0.945, 0.955)
    qc = get_qc("1q-qvm")
    qc.qam.noise_model = noise_model

    # bell state program (doesn't matter)
    p = Program()
    p += RESET()
    p += H(0)
    p += CNOT(0, 1)
    p.wrap_in_numshots_loop(10000)

    # Z experiment
    sz = ExperimentSetting(in_state=sZ(0), out_operator=sZ(0))
    e = Experiment(settings=[sz], program=p)

    results = qc.calibrate(e)

    # Z expectation value should just be 1 - 2 * readout_error
    np.isclose(results[0].expectation, 0.9, atol=0.01)
    assert results[0].total_counts == 20000