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

feihoo87 / waveforms / 6893865468

16 Nov 2023 04:49PM UTC coverage: 43.147% (+0.7%) from 42.467%
6893865468

push

github

feihoo87
update

7 of 17 new or added lines in 4 files covered. (41.18%)

588 existing lines in 10 files now uncovered.

7436 of 17234 relevant lines covered (43.15%)

3.87 hits per line

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

30.16
/waveforms/qlisp/simulator/__init__.py
1
import itertools
9✔
2
from functools import partial, reduce
9✔
3

4
import numpy as np
9✔
5

6
from waveforms.math.matricies import (CR, CX, CZ, SWAP, H, S, Sdag, SQiSWAP, T,
9✔
7
                                      Tdag, U, fSim, iSWAP, make_immutable,
8
                                      rfUnitary, sigmaI, sigmaX, sigmaY,
9
                                      sigmaZ)
10

11
try:
9✔
12
    import tensornetwork as tn
9✔
13
except ImportError:
9✔
14
    tn = None
9✔
15

16
__matrix_of_gates = {}
9✔
17

18

19
def regesterGateMatrix(gate, mat, N=None):
9✔
20
    if isinstance(mat, np.ndarray):
9✔
21
        mat = make_immutable(mat)
9✔
22
    if N is None:
9✔
23
        N = int(np.log2(mat.shape[0]))
9✔
24
    __matrix_of_gates[gate] = (mat, N)
9✔
25

26

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

45

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

60

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

72

73
def reduceSubspace(targets, N, inputMat, func, args):
9✔
74
    innerDim = 2**len(targets)
×
UNCOV
75
    outerDim = 2**(N - len(targets))
×
76

77
    targets = tuple(reversed([N - i - 1 for i in targets]))
×
78

79
    def index(targets, i, j):
×
80
        return splite_at(j, sorted(targets)) | place_at(i, targets)
×
81

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

97

98
def applySeq(seq, psi0=None):
9✔
UNCOV
99
    if psi0 is None:
×
100
        psi = np.array([1, 0], dtype=complex)
×
101
        N = 1
×
102
    else:
103
        psi = psi0
×
104
        N = int(np.round(np.log2(psi.shape[0])))
×
105

106
    if len(psi.shape) == 1:
×
UNCOV
107
        I = np.array([1, 0])
×
108
    else:
109
        I = np.eye(2)
×
110

111
    def func(psi, U):
×
112
        return U @ psi
×
113

114
    for gate, qubits in seq:
×
115
        if (isinstance(gate, tuple) and gate[0] in ['Measure', 'Delay']) or (
×
116
                isinstance(gate, str) and gate in ['Barrier']):
UNCOV
117
            continue
×
118
        if isinstance(qubits, tuple):
×
119
            M = max(qubits)
×
120
        else:
121
            M = qubits
×
122
            qubits = (qubits, )
×
UNCOV
123
        if M >= N:
×
124
            psi = reduce(np.kron, itertools.repeat(I, times=M - N + 1), psi)
×
UNCOV
125
            N = M + 1
×
126

UNCOV
127
        reduceSubspace(qubits, N, psi, func, (gate2mat(gate), ))
×
128

UNCOV
129
    return psi
×
130

131

132
def seq2mat(seq):
9✔
UNCOV
133
    return applySeq(seq, np.eye(2, dtype=complex))
×
134

135

136
def apply_gate(qubit_edges, gate, operating_qubits):
9✔
137
    if tn is None:
×
138
        raise ImportError('Please install tensornetwork first.')
×
139

140
    op = tn.Node(gate)
×
UNCOV
141
    for i, bit in enumerate(operating_qubits):
×
UNCOV
142
        tn.connect(qubit_edges[bit], op[i])
×
UNCOV
143
        qubit_edges[bit] = op[i + len(operating_qubits)]
×
144

145

146
def circuit_network(circ):
9✔
147
    if tn is None:
×
UNCOV
148
        raise ImportError('Please install tensornetwork first.')
×
149

UNCOV
150
    N = 0
×
151

152
    all_nodes = []
×
153

UNCOV
154
    with tn.NodeCollection(all_nodes):
×
155
        left_edges = []
×
156
        right_edges = []
×
157

UNCOV
158
        for gate, qubits in circ:
×
159
            if (isinstance(gate, tuple)
×
160
                    and gate[0] in ['Measure', 'Delay']) or (isinstance(
161
                        gate, str) and gate in ['Barrier']):
UNCOV
162
                continue
×
163
            if isinstance(qubits, tuple):
×
164
                M = max(qubits)
×
165
            else:
166
                M = qubits
×
167
                qubits = (qubits, )
×
168
            if M >= N:
×
169
                new_nodes = [tn.Node(np.eye(2)) for _ in range(M - N + 1)]
×
UNCOV
170
                left_edges.extend([node[0] for node in new_nodes])
×
171
                right_edges.extend([node[1] for node in new_nodes])
×
172
                N = M + 1
×
173

UNCOV
174
            gate_mat = gate2mat(gate)
×
175
            gate_tenser = gate_mat.reshape((2, 2) * len(qubits))
×
UNCOV
176
            apply_gate(left_edges, gate_tenser, qubits)
×
177

UNCOV
178
    return all_nodes, left_edges, right_edges, N
×
179

180

181
def apply_circuit(circ, qubits=None, init_state=None):
9✔
182
    if tn is None:
×
183
        raise ImportError('Please install tensornetwork first.')
×
184

UNCOV
185
    all_nodes, left_edges, right_edges, N = circuit_network(circ)
×
186
    if qubits is not None:
×
187
        assert len(qubits) == N
×
188
    else:
UNCOV
189
        qubits = list(range(N))
×
UNCOV
190
    if init_state is None:
×
191
        init_state_nodes = [
×
192
            tn.Node(np.array([1, 0], dtype=complex)) for i in range(N)
193
        ]
UNCOV
194
        init_state_edges = [init_state_nodes[i][0] for i in range(N)]
×
195
    else:
196
        init_state_nodes, init_state_edges = init_state
×
197

198
    all_nodes.extend(init_state_nodes)
×
199
    qubit_edges = [left_edges[q] for q in qubits]
×
200
    for i, q in enumerate(qubits):
×
UNCOV
201
        tn.connect(right_edges[i], init_state_edges[q])
×
UNCOV
202
    result = tn.contractors.optimal(all_nodes, output_edge_order=qubit_edges)
×
UNCOV
203
    return result.tensor.reshape(-1)
×
204

205

206
def circuit2mat(circ):
9✔
207
    if tn is None:
×
208
        raise ImportError('Please install tensornetwork first.')
×
209

210
    all_nodes, left_edges, right_edges, N = circuit_network(circ)
×
UNCOV
211
    result = tn.contractors.optimal(all_nodes,
×
212
                                    output_edge_order=left_edges + right_edges)
UNCOV
213
    return result.tensor.reshape((2**N, 2**N))
×
214

215

216
regesterGateMatrix('U', U, 1)
9✔
217
regesterGateMatrix('P', lambda p: U(theta=0, phi=0, lambda_=p), 1)
9✔
218
regesterGateMatrix('rfUnitary', rfUnitary, 1)
9✔
219
regesterGateMatrix('Rx', partial(rfUnitary, phi=0), 1)
9✔
220
regesterGateMatrix('Ry', partial(rfUnitary, phi=np.pi / 2), 1)
9✔
221
regesterGateMatrix('Rz', lambda p: U(theta=0, phi=0, lambda_=p), 1)
9✔
222
regesterGateMatrix('fSim', fSim, 2)
9✔
223

224
# one qubit
225
regesterGateMatrix('I', sigmaI())
9✔
226
regesterGateMatrix('X', -1j * sigmaX())
9✔
227
regesterGateMatrix('Y', -1j * sigmaY())
9✔
228
regesterGateMatrix('X/2', np.array([[1, -1j], [-1j, 1]]) / np.sqrt(2))
9✔
229
regesterGateMatrix('Y/2', np.array([[1, -1], [1, 1]]) / np.sqrt(2))
9✔
230
regesterGateMatrix('-X/2', np.array([[1, 1j], [1j, 1]]) / np.sqrt(2))
9✔
231
regesterGateMatrix('-Y/2', np.array([[1, 1], [-1, 1]]) / np.sqrt(2))
9✔
232
regesterGateMatrix('Z', sigmaZ())
9✔
233
regesterGateMatrix('S', S)
9✔
234
regesterGateMatrix('-S', Sdag)
9✔
235
regesterGateMatrix('H', H)
9✔
236

237
# non-clifford
238
regesterGateMatrix('T', T)
9✔
239
regesterGateMatrix('-T', Tdag)
9✔
240
regesterGateMatrix('W/2', rfUnitary(np.pi / 2, np.pi / 4))
9✔
241
regesterGateMatrix('-W/2', rfUnitary(-np.pi / 2, np.pi / 4))
9✔
242
regesterGateMatrix('V/2', rfUnitary(np.pi / 2, 3 * np.pi / 4))
9✔
243
regesterGateMatrix('-V/2', rfUnitary(-np.pi / 2, 3 * np.pi / 4))
9✔
244

245
# two qubits
246
regesterGateMatrix('CZ', CZ)
9✔
247
regesterGateMatrix('Cnot', CX)
9✔
248
regesterGateMatrix('CX', CX)
9✔
249
regesterGateMatrix('iSWAP', iSWAP)
9✔
250
regesterGateMatrix('SWAP', SWAP)
9✔
251
regesterGateMatrix('CR', CR)
9✔
252

253
# non-clifford
254
regesterGateMatrix('SQiSWAP', SQiSWAP)
9✔
255

256
if __name__ == '__main__':
9✔
257
    # Porter-Thomas distribution
258

UNCOV
259
    def randomSeq(depth, N):
×
UNCOV
260
        seq = []
×
UNCOV
261
        for i in range(depth):
×
UNCOV
262
            for j in range(N):
×
UNCOV
263
                seq.append((np.random.choice(['X/2', 'Y/2', 'W/2']), j))
×
UNCOV
264
            for j in range(i % 2, N, 2):
×
UNCOV
265
                seq.append(('SQiSWAP', (j, (j + 1) % N)))
×
UNCOV
266
        return seq
×
267

268
    p = []
×
269
    # run 1000 random circuit on 6 qubits
270
    for i in range(1000):
×
271
        print('    ', i, end='')
×
272
        seq = randomSeq(50, 6)
×
273
        psi = applySeq(seq)
×
274
        p.extend(list(np.abs(psi)**2))
×
275
        print('    ', i)
×
UNCOV
276
    p = np.asarray(p)
×
277

278
    # plot distribution of probabilities
279
    N = 2**6
×
280
    y, x = np.histogram(N * p, bins=50, density=True)
×
281

282
    import matplotlib.pyplot as plt
×
283

284
    plt.semilogy((x[:-1] + x[1:]) / 2, y)
×
285
    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