Example #1
0
def test_peak_on_ground_state():
    sdm = SparseDM(1)
    sdm.ensure_dense(0)

    p0, p1 = sdm.peak_measurement(0)
    assert p0 == 1
    assert p1 == 0
Example #2
0
def SimulateRandomClifford(circ, gauge, noise):
    # Compute the entanglement fidelity between the noisy circuit and the perfect circuit.
    # 1. Compute the Choi state for the perfect circuit.
    # 2. Compute the Choi state for the imperfect circuit.
    # 3. Take the inner product.

    start = time.time()

    perfect = qc.Circuit(title='Perfect Circuit')
    RandomCliffordCircuit(perfect, circ, gauge, 0)
    pdm = SparseDM(perfect.get_qubit_names())
    perfect.apply_to(pdm)

    #print("Perfect Choi state")
    #print(sdmc.full_dm.dm.ravel())

    noisy = qc.Circuit(title='Noisy Circuit')
    RandomCliffordCircuit(noisy, circ, gauge, noise)
    ndm = SparseDM(noisy.get_qubit_names())
    noisy.apply_to(ndm)

    fidelity = np.dot(pdm.full_dm.dm.ravel(), ndm.full_dm.dm.ravel())

    # print("fidelity = %g"% (fidelity))

    end = time.time()

    # print("gauge setting\n%s\ndone in %d seconds."% (np.array_str(gauge), end - start))

    return fidelity
Example #3
0
def test_ensure_dense_simple():
    sdm = SparseDM(10)
    sdm.ensure_dense(0)
    sdm.ensure_dense(1)

    assert len(sdm.classical) == 8
    assert len(sdm.idx_in_full_dm) == 2
    assert sdm.full_dm.no_qubits == 2
    assert np.allclose(sdm.trace(), 1)
Example #4
0
    def test_multiple_measurement_hadamard_on_classical(self):
        sdm = SparseDM(2)

        sdm.hadamard(0)

        meas = sdm.peak_multiple_measurements([0, 1])

        assert len(meas) == 2
        assert meas == [({0: 0, 1: 0}, 0.5), ({0: 1, 1: 0}, 0.5)]
Example #5
0
def test_peak_on_hadamard():
    sdm = SparseDM(1)

    hadamard = ptm.hadamard_ptm()
    sdm.apply_ptm(0, hadamard)

    p0, p1 = sdm.peak_measurement(0)

    assert np.allclose(p0, 0.5)
    assert np.allclose(p1, 0.5)
Example #6
0
    def test_majority_vote_on_excited_classical(self):
        bits = [1, 2, 3]
        sdm = SparseDM(bits)

        sdm.set_bit(1, 1)
        sdm.set_bit(3, 1)

        p = sdm.majority_vote(bits)
        assert np.allclose(p, 1)
        assert sdm._last_majority_vote_mask == 0
Example #7
0
def test_renormalize():
    sdm = SparseDM(2)

    sdm.hadamard(0)

    sdm.project_measurement(0, 1)

    assert np.allclose(sdm.trace(), 0.5)

    sdm.renormalize()

    assert np.allclose(sdm.trace(), 1)
Example #8
0
    def test_majority_vote_gs_classical(self):

        bits = [1, 2, 3]
        sdm = SparseDM(bits)

        assert sdm._last_majority_vote_array is None
        assert sdm._last_majority_vote_mask is None

        p = sdm.majority_vote(bits)

        assert sdm._last_majority_vote_mask == 0

        assert np.allclose(p, 0)
Example #9
0
def test_copy():
    sdm = SparseDM(5)
    sdm.classical.update({1: 1, 3: 1})
    sdm.ensure_dense(2)

    assert sdm.full_dm.no_qubits == 1
    assert len(sdm.classical) == 4

    sdm_copy = sdm.copy()

    assert len(sdm_copy.classical) == 4
    assert sdm_copy.classical == {0: 0, 1: 1, 3: 1, 4: 0}
    assert sdm_copy.classical is not sdm.classical
    assert sdm.full_dm is not sdm_copy.full_dm
    assert np.allclose(sdm.full_dm.to_array(), sdm_copy.full_dm.to_array())
Example #10
0
    def test_multiple_does_not_change(self):
        sdm = SparseDM(3)

        sdm.hadamard(0)
        sdm.hadamard(1)

        sdm.ensure_dense(0)
        sdm.ensure_dense(1)
        sdm.ensure_dense(2)

        before = sdm.full_dm.to_array()

        assert before.shape == (8, 8)
        sdm.peak_multiple_measurements([0, 1, 2])

        assert np.allclose(before, sdm.full_dm.to_array())
Example #11
0
    def test_majority_after_hadamard(self):

        bits = [1, 2, 3]
        sdm = SparseDM(bits)
        sdm.hadamard(1)
        sdm.hadamard(2)
        sdm.hadamard(3)

        p = sdm.majority_vote(bits)

        assert np.allclose(p, 0.5)

        sdm.hadamard(3)

        p = sdm.majority_vote(bits)

        assert np.allclose(p, 0.25)
Example #12
0
def test_peak_then_measure():
    sdm = SparseDM(1)

    assert np.allclose(sdm.trace(), 1)
    sdm.ensure_dense(0)
    assert np.allclose(sdm.trace(), 1)

    p0, p1 = sdm.peak_measurement(0)

    assert np.allclose(p0, 1)
    assert np.allclose(p1, 0)

    sdm.project_measurement(0, 0)

    assert len(sdm.classical) == 1
    assert 0 in sdm.classical
    assert sdm.classical[0] == 0
    assert len(sdm.idx_in_full_dm) == 0
    assert sdm.full_dm.no_qubits == 0
    assert np.allclose(sdm.trace(), 1)
Example #13
0
def test_peak_on_decay():
    sdm = SparseDM(1)
    sdm.classical[0] = 1

    p0, p1 = sdm.peak_measurement(0)

    assert np.allclose(p0, 0)
    assert np.allclose(p1, 1)

    sdm.amp_ph_damping(0, 0.02, 0)

    p0, p1 = sdm.peak_measurement(0)

    assert np.allclose(p0, 0.02)
    assert np.allclose(p1, 0.98)

    sdm.amp_ph_damping(0, 0.02, 0)

    p0, p1 = sdm.peak_measurement(0)

    assert np.allclose(p0, 0.02 + 0.98 * 0.02)
Example #14
0
    def test_majority_vote_on_excited_quantum(self):
        bits = [1, 2, 3]
        sdm = SparseDM(bits)

        sdm.rotate_y(1, np.pi)
        sdm.rotate_y(2, np.pi)
        sdm.rotate_y(3, 2 * np.pi)

        p = sdm.majority_vote(bits)
        assert np.allclose(p, 1)
        assert sdm._last_majority_vote_mask == 7
Example #15
0
def test_set_bit():
    sdm = SparseDM(10)
    sdm.set_bit(0, 1)

    assert sdm.classical[0] == 1

    sdm.hadamard(0)
    sdm.hadamard(0)
Example #16
0
    def test_multiple_measurement_hadamard_order2_regression(self):
        sdm = SparseDM(3)

        sdm.hadamard(0)
        sdm.hadamard(1)

        sdm.ensure_dense(0)
        sdm.ensure_dense(1)
        sdm.ensure_dense(2)

        meas = sdm.peak_multiple_measurements([0, 1, 2])

        assert len(meas) == 8
        for state, p in meas:
            print(meas)
            if state[2] == 0:
                assert np.allclose(p, 0.25)
            else:
                assert np.allclose(p, 0)
Example #17
0
    def test_majority_vote_invalid_results_error(self):
        bits = [1, 2, 3]
        sdm = SparseDM(bits)

        with pytest.raises(ValueError):
            sdm.majority_vote({1: "bla"})

        with pytest.raises(ValueError):
            sdm.majority_vote({1: 2})
Example #18
0
    def test_multiple_measurement_classical_prob(self):
        sdm = SparseDM(3)

        sdm.hadamard(0)
        sdm.hadamard(1)

        sdm.classical_probability = 0.7

        r = sdm.peak_multiple_measurements([0, 1, 2])

        total_prob = sum(prob for outcome, prob in r)

        assert total_prob == sdm.trace()
Example #19
0
def test_meas_on_ground_state():
    sdm = SparseDM(1)

    sdm.ensure_dense(0)

    sdm.project_measurement(0, 0)

    assert len(sdm.classical) == 1
    assert 0 in sdm.classical
    assert sdm.classical[0] == 0
    assert len(sdm.idx_in_full_dm) == 0
    assert sdm.full_dm.no_qubits == 0
    assert np.allclose(sdm.trace(), 1)
Example #20
0
    def test_multiple_measurement_hadamard_order1(self):
        sdm = SparseDM(3)

        sdm.hadamard(0)
        sdm.hadamard(2)

        sdm.ensure_dense(0)
        sdm.ensure_dense(1)
        sdm.ensure_dense(2)

        meas = sdm.peak_multiple_measurements([0, 1, 2])

        assert len(meas) == 8
        for state, p in meas:
            for x in state.values():
                assert x in [0, 1]
            if state[1] == 0:
                assert np.allclose(p, 0.25)
            else:
                assert np.allclose(p, 0)
Example #21
0
def test_meas_on_hadamard():
    sdm = SparseDM(1)
    sdm.hadamard(0)

    p0, p1 = sdm.peak_measurement(0)

    assert p0 == 0.5
    assert p1 == 0.5

    sdm.project_measurement(0, 1)

    print(sdm.full_dm.to_array())

    assert len(sdm.classical) == 1
    assert sdm.full_dm.no_qubits == 0
    assert sdm.classical[0] == 1
    assert np.allclose(sdm.trace(), 0.5)
Example #22
0
    def test_multiple_measurement_gs(self):
        sdm = SparseDM(3)

        sdm.ensure_dense(0)
        sdm.ensure_dense(1)
        sdm.ensure_dense(2)

        meas = sdm.peak_multiple_measurements([0, 1, 2])

        assert len(meas) == 8
        for state, p in meas:
            if state[0] == 0 and state[1] == 0 and state[2] == 0:
                assert np.allclose(p, 1)
            else:
                assert np.allclose(p, 0)
Example #23
0
    def test_override(self):
        qubit_list = ['swap', 'cp']
        with pytest.warns(UserWarning):
            # We did not provide any seed
            setup = quick_setup(qubit_list, noise_flag=False)
        b = Builder(setup)
        b < ('RotateY', 'swap', np.pi/2)
        b < ('RotateY', 'cp', np.pi/2)
        b < ('CZ', 'cp', 'swap')
        b < ('RotateY', 'cp', -np.pi/2)
        b.finalize()

        bell_circuit = b.circuit
        bell_state = SparseDM(bell_circuit.get_qubit_names())
        bell_circuit.apply_to(bell_state)
        diag = np.diag(bell_state.full_dm.to_array())

        assert np.abs(diag[0]-0.5) < 1e-10
        assert np.abs(diag[3]-0.5) < 1e-10
        assert np.abs(diag[1]) < 1e-10
        assert np.abs(diag[2]) < 1e-10
Example #24
0
    def test_make_imperfect_bell(self):
        qubit_list = ['swap', 'cp']
        with pytest.warns(UserWarning):
            # We did not provide any seed
            setup = quick_setup(qubit_list)
        b = Builder(setup)
        b.add_gate('RotateY', ['swap'], angle=np.pi/2)
        b.add_gate('RotateY', ['cp'], angle=np.pi/2)
        b.add_gate('CZ', ['cp', 'swap'])
        b.add_gate('RotateY', ['cp'], angle=-np.pi/2)
        b.finalize()

        bell_circuit = b.circuit
        bell_state = SparseDM(bell_circuit.get_qubit_names())
        bell_circuit.apply_to(bell_state)
        diag = np.diag(bell_state.full_dm.to_array())

        assert np.abs(diag[0]-0.5) < 1e-2
        assert np.abs(diag[3]-0.5) < 1e-2
        assert np.abs(diag[1]) < 3e-2
        assert np.abs(diag[2]) < 3e-2
Example #25
0
    def test_deferred_apply(self):
        sdm = SparseDM(1)

        assert 0 in sdm.classical

        p = ptm.hadamard_ptm()
        sdm.apply_ptm(0, p)

        assert 0 in sdm.classical
        assert 0 in sdm.single_ptms_to_do

        sdm.combine_and_apply_single_ptm(0)

        assert 0 not in sdm.classical

        assert 0 not in sdm.single_ptms_to_do
Example #26
0
    def test_qasm(self):
        qubit_list = ['swap', 'cp']
        with pytest.warns(UserWarning):
            # We did not provide any seed
            setup = quick_setup(qubit_list, noise_flag=False)
        b = Builder(setup)
        qasm0 = 'Ry 1.57079632679 swap'
        qasm1 = 'Ry 1.57079632679 cp'
        qasm2 = 'CZ cp swap'
        qasm3 = 'Ry -1.57079632679 cp'
        qasm_list = [qasm0, qasm1, qasm2, qasm3]
        b.add_qasm(qasm_list, qubits_first=False)
        b.finalize()

        bell_circuit = b.circuit
        bell_state = SparseDM(bell_circuit.get_qubit_names())
        bell_circuit.apply_to(bell_state)
        diag = np.diag(bell_state.full_dm.to_array())

        assert np.abs(diag[0]-0.5) < 1e-10
        assert np.abs(diag[3]-0.5) < 1e-10
        assert np.abs(diag[1]) < 1e-10
        assert np.abs(diag[2]) < 1e-10
Example #27
0
class Controller:
    def __init__(self,
                 filename=None,
                 setup=None,
                 random_state=None,
                 seed=None,
                 qubits=None,
                 circuits=None,
                 circuit_lists=None,
                 adjust_gates=None,
                 measurement_gates=None,
                 angle_convert_matrices=None,
                 mbits=None):

        """
        qubits: list of qubits in the experiment
        mbits: the set of bits to receive measurements
        circuits: dictionary of circuits to apply to a state
            to perform an operation.
        circuit_lists: corresponding circuit lists (as output by qsoverlay
            builder for saving purposes)
        msmt_circuits: dictionary of circuits to measure a state.
        adjust_gates: a list of adjustable gates in a circuit
            that the user might pass parameters to when they run
            the circuit.
        measurement_gates: a set of Measurement type operators
            to extract extra details about the measurements made.
        """

        self.circuits = circuits or {}
        self.circuit_lists = circuit_lists or {}
        if 'record' in self.circuits:
            raise ValueError('record is a protected keyword')
        if any([type(c) == int for c in self.circuits]):
            raise ValueError('Circuits must not use integers for labels')

        self.mbits = mbits or []
        self.qubits = qubits or []
        self.adjust_gates = adjust_gates or {}
        self.angle_convert_matrices = angle_convert_matrices or {}
        self.measurement_gates = measurement_gates or {}
        self.state = None

        if filename is not None:
            self.load(filename, setup, random_state, seed)

        self.make_state()

    def load(self, filename, setup, random_state=None, seed=None):

        with open(filename, 'r') as infile:
            data = json.load(infile)

        if type(setup) == str:
            setup = Setup(filename=setup, state=random_state, seed=seed)

        self.mbits = data['mbits']
        self.qubits = data['qubits']
        self.angle_convert_matrices = {
            key: np.array(val)
            for key, val in data['angle_convert_matrices'].items()
        }

        b = Builder(setup)
        for name, cl in data['circuit_lists'].items():
            b.new_circuit()
            adjust_gates = b.add_circuit_list(cl)
            b.finalize()
            self.circuits[name] = b.circuit
            self.circuit_lists[name] = cl
            self.adjust_gates[name] = [
                ag for ag in adjust_gates
                if type(ag) is not Measurement]
            self.measurement_gates[name] = [
                ag for ag in adjust_gates
                if type(ag) is Measurement]
            if name in data['angle_convert_matrices']:
                self.angle_convert_matrices = \
                    data['angle_convert_matrices'][name]

    def save(self, filename):
        data = {
            'mbits': self.mbits,
            'qubits': self.qubits,
            'circuit_lists': self.circuit_lists,
            'angle_convert_matrices': {
                key: val.tolist()
                for key, val in self.angle_convert_matrices.items()}
        }

        with open(filename, 'w') as outfile:
            json.dump(data, outfile)

    def make_state(self, dense_qubits=None):
        self.state = SparseDM(self.qubits + self.mbits)
        if dense_qubits is not None:
            for qubit in dense_qubits:
                self.state.ensure_dense(qubit)

    def apply_circuit(self, circuit):

        """
        Applies a circuit to the state.

        Each entry is either:
        a) a string corresponding to an entry in self.circuits
        b) a tuple or list with the first entry a string corresponding
            to an entry in self.circuits and the remaining entries
            angles to input for self.adjust_gates.
        c) a tuple or list with the first entry the reserved keyword
            'record', and the remaining entries a list of mbits to
            store the current value of.
        d) a pair (n, circuit), where circuit is one of the above,
            and n is the number of times to repeat the circuit.
        """

        # Record is a reserved keyword to copy the output
        # from a set of classical bits to return to the user.

        if type(circuit) is list or type(circuit) is tuple:

            if circuit[0] == 'record':
                output = []
                for mbit in circuit[1:]:
                    output.append(self.state.classical[mbit])
                return output

            op_name = circuit[0]
            if type(op_name) == int:
                return_data = []
                for _ in range(op_name):
                    return_data.append(self.apply_circuit(circuit[1]))
                return return_data

            else:
                if op_name in self.angle_convert_matrices:
                    angles = self.angle_convert_matrices[op_name] @ circuit[1:]
                else:
                    angles = circuit[1:]
                for gate, param in zip(
                        self.adjust_gates[op_name], angles):
                    if not isinstance(param, tuple):
                        param = (param,)
                    gate.adjust(*param)
                self.circuits[op_name].apply_to(self.state,
                                                apply_all_pending=False)

        else:
            op_name = circuit
            self.circuits[op_name].apply_to(self.state,
                                            apply_all_pending=False)

        if op_name in self.measurement_gates:
            return_data = [{
                'probabilities': m.probabilities[-1],
                'projects': m.projects[-1],
                'measurements': m.measurements[-1]}
                for m in self.measurement_gates[op_name]]
            return return_data

        return None

    def __lt__(self, circuit):
        self.apply_circuit(circuit)

    def apply_circuit_list(self, circuit_list):
        """
        Apply a set of operations to a state.

        circuit_list: a list of circuits to apply.
        """
        output_list = []
        for circuit in circuit_list:

            # Record is a reserved keyword to copy the output
            # from a set of classical bits to return to the user.
            output = self.apply_circuit(circuit)
            if output is not None:
                output_list.append(output)

        return output_list

    def simulate_tomo(self, circuit,
                      tomo_circuits,
                      measurement_model,
                      num_measurements,
                      output_format, data_type):
        """
        Takes the current system state, copies it,
        applies multiple tomography circuits, and runs them through
        models for the measurement to return thresholded voltages.
        """
        data = []
        for tomo_circuit in tomo_circuits:
            self.make_state()
            self < circuit
            self < tomo_circuit
            self.state.renormalize()
            rho_dist = self.state.peak_multiple_measurements(
                measurement_model.qubits)
            data.append(measurement_model.sample(
                rho_dist, num_measurements, data_type=data_type,
                output_format=output_format))
        return data

    def get_expectation_values(self, msmts, num_repetitions=None):
        """
        Measures a set of Pauli strings on the current state.
        If num_repetitions is None this is performed perfectly.
        Otherwise, we treat the calculated value as a bernoulli
        random variable we are attempting to approximate, and
        sample an answer.

        input: msmts: list of measurement dictionaries, containing
        'X', 'Y', or 'Z' for each non-trivial qubit label.
        """

        results = []
        self.state.apply_all_pending()
        self.state.renormalize()
        dm = self.state.full_dm.to_array()

        for msmt in msmts:

            mult = 1

            # Make Pauli list
            pauli_list = [1] * len(self.state.idx_in_full_dm)
            for qubit in msmt:
                if qubit not in self.state.idx_in_full_dm:
                    if msmt[qubit] == 'Z':
                        mult *= (-1) ** self.state.classical[qubit]
                    elif msmt[qubit] in ['X', 'Y']:
                        mult = 0
                    else:
                        raise ValueError('qubit measurements must be X, Y, Z')
                else:
                    pauli_list[self.state.idx_in_full_dm[qubit]] = msmt[qubit]

            # Make measurement operator
            op = pauli_dic[pauli_list[0]]
            for label in pauli_list[1:]:
                op = np.kron(pauli_dic[label], op)

            result = mult * np.trace(op @ dm)

            assert np.imag(result) < 1e-9
            result = float(np.real(result))

            if num_repetitions is not None:
                bernoulli_rv = (1 - result) / 2
                if -1e-6 < bernoulli_rv <= 0:
                    noisy_result = 0
                elif 1 <= bernoulli_rv < 1 + 1e-6:
                    noisy_result = 1
                else:
                    try:
                        noisy_result = np.random.beta(bernoulli_rv *
                                                      num_repetitions,
                                                      (1 - bernoulli_rv) *
                                                      num_repetitions)
                    except Exception:
                        raise ValueError(
                            'My bernoulli random variable is weird: {}'
                            .format(bernoulli_rv))

                results.append(1 - 2 * noisy_result)
            else:
                results.append(result)

        return np.array(results)

    def get_prob_all_zero(self, qubits):

        """
        Returns the probability that all qubits in qubits
        will return a 0 measurement (regardless of any other qubit
        measurement).
        """

        self.state.apply_all_pending()
        self.state.renormalize()

        indices = [self.state.idx_in_full_dm[q] for q in qubits]
        diagonal = self.state.full_dm.get_diag()

        return sum([x for j, x in enumerate(diagonal) if
                    all([(j // 2 ** i) % 2 == 0 for i in indices])])
Example #28
0
 def make_state(self, dense_qubits=None):
     self.state = SparseDM(self.qubits + self.mbits)
     if dense_qubits is not None:
         for qubit in dense_qubits:
             self.state.ensure_dense(qubit)
Example #29
0
 def test_init(self):
     sdm = SparseDM(10)
     assert sdm.no_qubits == 10
     assert len(sdm.classical) == 10
     assert sdm.classical[0] == 0
Example #30
0
def test_cphase_simple():
    sdm = SparseDM(2)
    sdm.cphase(0, 1)
    assert sdm.full_dm.no_qubits == 2