• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

feihoo87 / waveforms / 6534953321

16 Oct 2023 02:19PM UTC coverage: 35.674% (-22.7%) from 58.421%
6534953321

push

github

feihoo87
fix Coveralls

5913 of 16575 relevant lines covered (35.67%)

3.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.23
/waveforms/qlisp/simulator/simple.py
1
from concurrent.futures import process
9✔
2
import itertools
9✔
3
from functools import partial, reduce
9✔
4

5
import numpy as np
9✔
6

7
from .mat import U, fSim, make_immutable, rfUnitary
9✔
8

9
__matrix_of_gates = {}
9✔
10

11

12
def regesterGateMatrix(gate, mat, N=None, docs=''):
9✔
13
    if isinstance(mat, np.ndarray):
9✔
14
        mat = make_immutable(mat)
9✔
15
    if N is None:
9✔
16
        N = round(np.log2(mat.shape[0]))
9✔
17
    __matrix_of_gates[gate] = (mat, N, docs)
9✔
18

19

20
def gate_name(gate):
9✔
21
    if isinstance(gate, tuple):
9✔
22
        return gate_name(gate[0])
×
23
    elif isinstance(gate, str):
9✔
24
        return gate
9✔
25
    else:
26
        raise ValueError(f'Unexcept gate {gate}')
×
27

28

29
def gate2mat(gate):
9✔
30
    if isinstance(gate, str) and gate in __matrix_of_gates:
9✔
31
        return __matrix_of_gates[gate][:2]
9✔
32
    elif isinstance(gate, tuple) and gate[0] in __matrix_of_gates:
×
33
        if callable(__matrix_of_gates[gate[0]][0]):
×
34
            return __matrix_of_gates[gate[0]][0](
×
35
                *gate[1:]), __matrix_of_gates[gate[0]][1]
36
        else:
37
            raise ValueError(
×
38
                f"Could not call {gate[0]}(*{gate[1:]}), `{gate[0]}` is not callable."
39
            )
40
    elif gate_name(gate) == 'C':
×
41
        U, N = gate2mat(gate[1])
×
42
        ret = np.eye(2 * U.shape[0], dtype=complex)
×
43
        ret[U.shape[0]:, U.shape[0]:] = U
×
44
        return ret, N + 1
×
45
    else:
46
        raise ValueError(f'Unexcept gate {gate}')
×
47

48

49
def splite_at(l, bits):
9✔
50
    """将 l 的二进制位于 bits 所列的位置上断开插上0
51
    
52
    如 splite_at(int('1111',2), [0,2,4,6]) == int('10101010', 2)
53
    bits 必须从小到大排列
54
    """
55
    r = l
9✔
56
    for n in bits:
9✔
57
        mask = (1 << n) - 1
9✔
58
        low = r & mask
9✔
59
        high = r - low
9✔
60
        r = (high << 1) + low
9✔
61
    return r
9✔
62

63

64
def place_at(l, bits):
9✔
65
    """将 l 的二进制位置于 bits 所列的位置上
66
    
67
    如 place_at(int('10111',2), [0,2,4,5,6]) == int('01010101', 2)
68
    """
69
    r = 0
9✔
70
    for index, n in enumerate(bits):
9✔
71
        b = (l >> index) & 1
9✔
72
        r += b << n
9✔
73
    return r
9✔
74

75

76
def reduceSubspace(targets, N, inputMat, func, args):
9✔
77
    innerDim = 2**len(targets)
9✔
78
    outerDim = 2**(N - len(targets))
9✔
79

80
    targets = tuple(reversed([N - i - 1 for i in targets]))
9✔
81

82
    def index(targets, i, j):
9✔
83
        return splite_at(j, sorted(targets)) | place_at(i, targets)
9✔
84

85
    if len(inputMat.shape) == 1:
9✔
86
        for k in range(outerDim):
×
87
            innerIndex = [index(targets, i, k) for i in range(innerDim)]
×
88
            inputMat[innerIndex] = func(inputMat[innerIndex], *args)
×
89
    else:
90
        for k, l in itertools.product(range(outerDim), repeat=2):
9✔
91
            innerIndex = np.asarray(
9✔
92
                [[index(targets, i, k),
93
                  index(targets, j, l)]
94
                 for i, j in itertools.product(range(innerDim), repeat=2)]).T
95
            sub = inputMat[innerIndex[0], innerIndex[1]].reshape(
9✔
96
                (innerDim, innerDim))
97
            inputMat[innerIndex[0], innerIndex[1]] = func(sub, *args).flatten()
9✔
98
    return inputMat
9✔
99

100

101
def _apply_gate(gate, inputMat, unitary_process, qubits, N):
9✔
102
    U, n = gate2mat(gate)
9✔
103
    if len(qubits) == n and all(isinstance(qubit, int) for qubit in qubits):
9✔
104
        reduceSubspace(qubits, N, inputMat, unitary_process, (U, ))
9✔
105
    elif n == 1 and all(isinstance(qubit, int) for qubit in qubits):
×
106
        for qubit in qubits:
×
107
            reduceSubspace([qubit], N, inputMat, unitary_process, (U, ))
×
108
    elif len(qubits) == n and all(
×
109
            isinstance(qubit, [tuple, list]) for qubit in qubits):
110
        for qubit_tuple in zip(*qubits):
×
111
            reduceSubspace(qubit_tuple, N, inputMat, unitary_process, (U, ))
×
112
    else:
113
        raise ValueError(f'Unexcept gate {gate} and qubits {qubits}')
×
114

115

116
def _measure_process(rho):
9✔
117
    return np.array([[rho[0, 0], 0], [0, rho[1, 1]]])
×
118

119

120
def _reset_process(rho, p1):
9✔
121
    s0 = np.array([[rho[0, 0] + rho[1, 1], 0], [0, 0]])
×
122
    s1 = np.array([[0, 0], [0, rho[0, 0] + rho[1, 1]]])
×
123
    return (1 - p1) * s0 + p1 * s1
×
124

125

126
def _decohherence_process(rho, Gamma_t, gamma_t):
9✔
127
    rho00 = rho[0, 0] + rho[1, 1] * (1 - np.exp(-Gamma_t))
×
128
    rho11 = rho[1, 1] * np.exp(-Gamma_t)
×
129
    rho01 = rho[0, 1] * np.exp(-Gamma_t / 2 - gamma_t**2)
×
130
    rho10 = rho[1, 0] * np.exp(-Gamma_t / 2 - gamma_t**2)
×
131
    return np.array([[rho00, rho01], [rho10, rho11]])
×
132

133

134
def applySeq(seq, psi0=None):
9✔
135

136
    def _set_vector_to_rho(psi):
×
137
        psi = psi.reshape(-1, 1).conj() @ psi.reshape(1, -1)
×
138
        unitary_process = lambda psi, U: U @ psi @ U.T.conj()
×
139
        return psi, unitary_process, np.array([[1, 0], [0, 0]])
×
140

141
    if psi0 is None:
×
142
        psi = np.array([1, 0], dtype=complex)
×
143
        N = 1
×
144
    else:
145
        psi = psi0
×
146
        N = round(np.log2(psi.shape[0]))
×
147

148
    psi0 = np.array([1, 0])
×
149
    unitary_process = lambda psi, U: U @ psi
×
150

151
    if psi.ndim == 2:
×
152
        psi, unitary_process, psi0 = _set_vector_to_rho(psi)
×
153

154
    for gate, *qubits in seq:
×
155
        M = max(qubits)
×
156
        if M >= N:
×
157
            psi = reduce(np.kron, itertools.repeat(psi0, times=M - N + 1), psi)
×
158
            N = M + 1
×
159

160
        if gate_name(gate) in ['Barrier']:
×
161
            continue
×
162
        if gate_name(gate) in ['Delay']:
×
163
            if len(gate) == 2:
×
164
                continue
×
165
            else:
166
                if len(gate) == 3:
×
167
                    _, t, T1 = gate
×
168
                    Gamma_t = t / T1
×
169
                    gamma_t = 0
×
170
                else:
171
                    _, t, T1, Tphi = gate
×
172
                    Gamma_t = t / T1
×
173
                    gamma_t = t / Tphi
×
174
        if gate_name(gate) in ['Reset']:
×
175
            if isinstance(gate, tuple) and len(gate) == 2:
×
176
                _, p1 = gate
×
177
            else:
178
                p1 = 0.0
×
179
        if gate_name(gate) in ['Measure', 'Reset', 'Delay'] and psi.ndim == 1:
×
180
            psi, unitary_process, psi0 = _set_vector_to_rho(psi)
×
181

182
        if gate_name(gate) == 'Measure':
×
183
            reduceSubspace(qubits, N, psi, _measure_process, ())
×
184
        elif gate_name(gate) == 'Reset':
×
185
            reduceSubspace(qubits, N, psi, _reset_process, (p1, ))
×
186
        elif gate_name(gate) == 'Delay':
×
187
            reduceSubspace(qubits, N, psi, _decohherence_process,
×
188
                           (Gamma_t, gamma_t))
189
        else:
190
            _apply_gate(gate, psi, unitary_process, qubits, N)
×
191

192
    return psi
×
193

194

195
def seq2mat(seq, U=None):
9✔
196
    I = np.eye(2, dtype=complex)
9✔
197
    if U is None:
9✔
198
        U = np.eye(2, dtype=complex)
9✔
199
        N = 1
9✔
200
    else:
201
        N = round(np.log2(U.shape[0]))
×
202

203
    unitary_process = lambda U0, U: U @ U0
9✔
204

205
    for gate, *qubits in seq:
9✔
206
        M = max(qubits)
9✔
207
        if M >= N:
9✔
208
            U = reduce(np.kron, itertools.repeat(I, times=M - N + 1), U)
9✔
209
            N = M + 1
9✔
210
        if gate_name(gate) in ['Delay', 'Barrier']:
9✔
211
            continue
×
212
        if gate_name(gate) in ['Measure', 'Reset']:
9✔
213
            raise ValueError(
×
214
                'Measure and Reset must be applied to a state vector')
215
        else:
216
            _apply_gate(gate, U, unitary_process, qubits, N)
9✔
217
    return U
9✔
218

219

220
regesterGateMatrix('U', U, 1)
9✔
221
regesterGateMatrix('u1', lambda p: U(theta=0, phi=0, lambda_=p), 1)
9✔
222
regesterGateMatrix('u2', lambda phi, lam: U(np.pi / 2, phi, lam), 1)
9✔
223
regesterGateMatrix('u3', U, 1)
9✔
224
regesterGateMatrix('P', lambda p: U(theta=0, phi=0, lambda_=p), 1)
9✔
225
regesterGateMatrix('rfUnitary', rfUnitary, 1)
9✔
226
regesterGateMatrix('R', lambda phi: rfUnitary(np.pi / 2, phi), 1)
9✔
227
regesterGateMatrix('Rx', partial(rfUnitary, phi=0), 1)
9✔
228
regesterGateMatrix('Ry', partial(rfUnitary, phi=np.pi / 2), 1)
9✔
229
regesterGateMatrix('Rz', lambda p: U(theta=0, phi=0, lambda_=p), 1)
9✔
230
regesterGateMatrix('fSim', fSim, 2)
9✔
231
regesterGateMatrix('Cphase', lambda phi: fSim(theta=0, phi=phi), 2)
9✔
232

233
# one qubit
234
regesterGateMatrix('I', np.array([[1, 0], [0, 1]]))
9✔
235
regesterGateMatrix('X', np.array([[0, -1j], [-1j, 0]]))
9✔
236
regesterGateMatrix('Y', np.array([[0, -1], [1, 0]]))
9✔
237
regesterGateMatrix('X/2', np.array([[1, -1j], [-1j, 1]]) / np.sqrt(2))
9✔
238
regesterGateMatrix('Y/2', np.array([[1, -1], [1, 1]]) / np.sqrt(2))
9✔
239
regesterGateMatrix('-X/2', np.array([[1, 1j], [1j, 1]]) / np.sqrt(2))
9✔
240
regesterGateMatrix('-Y/2', np.array([[1, 1], [-1, 1]]) / np.sqrt(2))
9✔
241
regesterGateMatrix('Z', np.array([[1, 0], [0, -1]]))
9✔
242
regesterGateMatrix('S', np.array([[1, 0], [0, 1j]]))
9✔
243
regesterGateMatrix('-S', np.array([[1, 0], [0, -1j]]))
9✔
244
regesterGateMatrix('H', np.array([[1, 1], [1, -1]]) / np.sqrt(2))
9✔
245

246
# non-clifford
247
regesterGateMatrix('T',
9✔
248
                   np.array([[1, 0], [0, 1 / np.sqrt(2) + 1j / np.sqrt(2)]]))
249
regesterGateMatrix('-T',
9✔
250
                   np.array([[1, 0], [0, 1 / np.sqrt(2) - 1j / np.sqrt(2)]]))
251
regesterGateMatrix('W/2', rfUnitary(np.pi / 2, np.pi / 4))
9✔
252
regesterGateMatrix('-W/2', rfUnitary(-np.pi / 2, np.pi / 4))
9✔
253
regesterGateMatrix('V/2', rfUnitary(np.pi / 2, 3 * np.pi / 4))
9✔
254
regesterGateMatrix('-V/2', rfUnitary(-np.pi / 2, 3 * np.pi / 4))
9✔
255

256
# two qubits
257
regesterGateMatrix(
9✔
258
    'CZ', np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]]))
259
regesterGateMatrix(
9✔
260
    'Cnot', np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]))
261
regesterGateMatrix(
9✔
262
    'iSWAP',
263
    np.array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]]))
264
regesterGateMatrix(
9✔
265
    'SWAP', np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]))
266
regesterGateMatrix(
9✔
267
    'CR',
268
    np.array([[1, 1j, 0, 0], [1j, 1, 0, 0], [0, 0, 1, -1j], [0, 0, -1j, 1]]) /
269
    np.sqrt(2))
270

271
# non-clifford
272
regesterGateMatrix(
9✔
273
    'SQiSWAP',
274
    np.array([[1, 0, 0, 0], [0, 1 / np.sqrt(2), 1j / np.sqrt(2), 0],
275
              [0, 1j / np.sqrt(2), 1 / np.sqrt(2), 0], [0, 0, 0, 1]]))
276

277
if __name__ == '__main__':
9✔
278
    # Porter-Thomas distribution
279

280
    def randomSeq(depth, N):
×
281
        seq = []
×
282
        for i in range(depth):
×
283
            for j in range(N):
×
284
                seq.append((np.random.choice(['X/2', 'Y/2', 'W/2']), j))
×
285
            for j in range(i % 2, N, 2):
×
286
                seq.append(('SQiSWAP', j, (j + 1) % N))
×
287
        return seq
×
288

289
    p = []
×
290
    # run 1000 random circuit on 6 qubits
291
    for i in range(1000):
×
292
        print('    ', i, end='')
×
293
        seq = randomSeq(50, 6)
×
294
        psi = applySeq(seq)
×
295
        p.extend(list(np.abs(psi)**2))
×
296
        print('    ', i)
×
297
    p = np.asarray(p)
×
298

299
    # plot distribution of probabilities
300
    N = 2**6
×
301
    y, x = np.histogram(N * p, bins=50, density=True)
×
302

303
    import matplotlib.pyplot as plt
×
304

305
    plt.semilogy((x[:-1] + x[1:]) / 2, y)
×
306
    plt.show()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc