Trajectree 0.0.4__py3-none-any.whl → 0.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trajectree/fock_optics/devices.py +129 -27
- trajectree/fock_optics/light_sources.py +8 -2
- trajectree/fock_optics/measurement.py +73 -37
- trajectree/fock_optics/noise_models.py +112 -2
- trajectree/{optical_quant_info.py → fock_optics/optical_quant_info.py} +15 -5
- trajectree/fock_optics/outputs.py +1 -1
- trajectree/quant_info/circuit.py +251 -0
- trajectree/quant_info/noise_models.py +24 -0
- trajectree/sequence/swap.py +48 -24
- trajectree/trajectory.py +289 -63
- {trajectree-0.0.4.dist-info → trajectree-0.0.5.dist-info}/METADATA +2 -1
- trajectree-0.0.5.dist-info/RECORD +18 -0
- {trajectree-0.0.4.dist-info → trajectree-0.0.5.dist-info}/WHEEL +1 -1
- trajectree-0.0.4.dist-info/RECORD +0 -16
- {trajectree-0.0.4.dist-info → trajectree-0.0.5.dist-info}/licenses/LICENSE +0 -0
- {trajectree-0.0.4.dist-info → trajectree-0.0.5.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
from quimb.tensor import MatrixProductOperator as mpo
|
|
2
|
+
from trajectree.trajectory import quantum_channel, trajectory_evaluator
|
|
3
|
+
import numpy as np
|
|
4
|
+
from qutip_qip.operations import H, CNOT, S, T, X, Z, CZ, RY, RZ
|
|
5
|
+
from .noise_models import amplitude_damping, phase_damping
|
|
6
|
+
from trajectree.fock_optics.utils import create_vacuum_state
|
|
7
|
+
from qutip import basis, tensor
|
|
8
|
+
import time
|
|
9
|
+
from scipy import sparse as sp
|
|
10
|
+
import copy
|
|
11
|
+
from functools import lru_cache
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Circuit:
|
|
16
|
+
def __init__(self, num_qubits=-1, backend = 'tensor'):
|
|
17
|
+
self.num_qubits = num_qubits
|
|
18
|
+
self.quantum_channel_list = []
|
|
19
|
+
self.expectation_ops = []
|
|
20
|
+
self.backend = backend
|
|
21
|
+
|
|
22
|
+
if num_qubits > 0:
|
|
23
|
+
trajectree_init = [sp.eye(2)]
|
|
24
|
+
self.quantum_channel_list.append(quantum_channel(N = 2, num_modes = num_qubits, formalism = "kraus", kraus_ops_tuple = ((0,), trajectree_init), backend = self.backend, name = "trajectree_init"))
|
|
25
|
+
if self.backend == 'tensor':
|
|
26
|
+
self.psi = create_vacuum_state(num_qubits, N=2)
|
|
27
|
+
elif self.backend == 'statevector':
|
|
28
|
+
self.psi = tensor([basis(2, 0)] * self.num_qubits)
|
|
29
|
+
|
|
30
|
+
def create_trajectree(self, cache_size=2, max_cache_nodes=-1):
|
|
31
|
+
self.t_eval = trajectory_evaluator(self.quantum_channel_list, cache_size = cache_size, max_cache_nodes = max_cache_nodes, backend = self.backend, calc_expectation = True)
|
|
32
|
+
|
|
33
|
+
def H_gate(self, idx, is_expectation = False, tag = "H gate"):
|
|
34
|
+
if self.backend == 'statevector':
|
|
35
|
+
quantum_channel_H = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([idx], H(0).get_compact_qobj()), backend = self.backend, name = tag)
|
|
36
|
+
elif self.backend == "tensor":
|
|
37
|
+
dense_op = H(0).get_compact_qobj().full()
|
|
38
|
+
H_MPO = mpo.from_dense(dense_op, dims = 2, sites = (idx,), L=self.num_qubits, tags=tag)
|
|
39
|
+
quantum_channel_H = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = H_MPO, backend = self.backend, name = tag)
|
|
40
|
+
|
|
41
|
+
if is_expectation:
|
|
42
|
+
self.expectation_ops.append(quantum_channel_H)
|
|
43
|
+
else:
|
|
44
|
+
self.quantum_channel_list.append(quantum_channel_H)
|
|
45
|
+
|
|
46
|
+
def CNOT_gate(self, control_idx, target_idx, tag = "CNOT gate"):
|
|
47
|
+
if self.backend == 'statevector':
|
|
48
|
+
quantum_channel_CX = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([control_idx, target_idx], CNOT(0,1).get_compact_qobj()), backend = self.backend, name = tag)
|
|
49
|
+
elif self.backend == 'tensor':
|
|
50
|
+
dense_op = CNOT(0,1).get_compact_qobj().full()
|
|
51
|
+
CNOT_MPO = mpo.from_dense(dense_op, dims = 2, sites = (control_idx, target_idx), L=self.num_qubits, tags=tag)
|
|
52
|
+
quantum_channel_CX = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = CNOT_MPO, backend = self.backend, name = tag)
|
|
53
|
+
|
|
54
|
+
self.quantum_channel_list.append(quantum_channel_CX)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def CZ_gate(self, control_idx, target_idx, tag = "CZ gate"):
|
|
58
|
+
if self.backend == 'statevector':
|
|
59
|
+
quantum_channel_CZ = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([control_idx, target_idx], CZ(0,1).get_compact_qobj()), backend = self.backend, name = tag)
|
|
60
|
+
elif self.backend == 'tensor':
|
|
61
|
+
dense_op = CZ(0,1).get_compact_qobj().full()
|
|
62
|
+
CZ_MPO = mpo.from_dense(dense_op, dims = 2, sites = (control_idx, target_idx), L=self.num_qubits, tags=tag)
|
|
63
|
+
quantum_channel_CZ = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = CZ_MPO, backend = self.backend, name = tag)
|
|
64
|
+
|
|
65
|
+
self.quantum_channel_list.append(quantum_channel_CZ)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def S_gate(self, idx, is_expectation = False, tag = "S gate"):
|
|
69
|
+
if self.backend == 'statevector':
|
|
70
|
+
quantum_channel_S = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([idx], S(0).get_compact_qobj()), backend = self.backend, name = tag)
|
|
71
|
+
elif self.backend == 'tensor':
|
|
72
|
+
dense_op = S(0).get_compact_qobj().full()
|
|
73
|
+
S_MPO = mpo.from_dense(dense_op, dims = 2, sites = (idx,), L=self.num_qubits, tags=tag)
|
|
74
|
+
quantum_channel_S = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = S_MPO, backend = self.backend, name = tag)
|
|
75
|
+
|
|
76
|
+
if is_expectation:
|
|
77
|
+
self.expectation_ops.append(quantum_channel_S)
|
|
78
|
+
else:
|
|
79
|
+
self.quantum_channel_list.append(quantum_channel_S)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def RY_gate(self, theta, idx, is_expectation = False, tag = "RY gate"):
|
|
83
|
+
if self.backend == 'statevector':
|
|
84
|
+
quantum_channel_RY = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([idx], RY(0, theta).get_compact_qobj()), backend = self.backend, name = tag)
|
|
85
|
+
elif self.backend == 'tensor':
|
|
86
|
+
dense_op = RY(0, theta).get_compact_qobj().full()
|
|
87
|
+
RY_MPO = mpo.from_dense(dense_op, dims = 2, sites = (idx,), L=self.num_qubits, tags=tag)
|
|
88
|
+
quantum_channel_RY = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = RY_MPO, backend = self.backend, name = tag)
|
|
89
|
+
|
|
90
|
+
if is_expectation:
|
|
91
|
+
self.expectation_ops.append(quantum_channel_RY)
|
|
92
|
+
else:
|
|
93
|
+
self.quantum_channel_list.append(quantum_channel_RY)
|
|
94
|
+
|
|
95
|
+
def RZ_gate(self, theta, idx, is_expectation = False, tag = "RZ gate"):
|
|
96
|
+
if self.backend == 'statevector':
|
|
97
|
+
quantum_channel_RZ = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([idx], RZ(0, theta).get_compact_qobj()), backend = self.backend, name = tag)
|
|
98
|
+
elif self.backend == 'tensor':
|
|
99
|
+
dense_op = RZ(0, theta).get_compact_qobj().full()
|
|
100
|
+
RZ_MPO = mpo.from_dense(dense_op, dims = 2, sites = (idx,), L=self.num_qubits, tags=tag)
|
|
101
|
+
quantum_channel_RZ = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = RZ_MPO, backend = self.backend, name = tag)
|
|
102
|
+
|
|
103
|
+
if is_expectation:
|
|
104
|
+
self.expectation_ops.append(quantum_channel_RZ)
|
|
105
|
+
else:
|
|
106
|
+
self.quantum_channel_list.append(quantum_channel_RZ)
|
|
107
|
+
|
|
108
|
+
def T_gate(self, idx, is_expectation = False, tag = "T gate"):
|
|
109
|
+
if self.backend == 'statevector':
|
|
110
|
+
quantum_channel_T = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([idx], T(0).get_compact_qobj()), backend = self.backend, name = tag)
|
|
111
|
+
elif self.backend == 'tensor':
|
|
112
|
+
dense_op = T(0).get_compact_qobj().full()
|
|
113
|
+
T_MPO = mpo.from_dense(dense_op, dims = 2, sites = (idx,), L=self.num_qubits, tags=tag)
|
|
114
|
+
quantum_channel_T = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = T_MPO, backend = self.backend, name = tag)
|
|
115
|
+
|
|
116
|
+
if is_expectation:
|
|
117
|
+
self.expectation_ops.append(quantum_channel_T)
|
|
118
|
+
else:
|
|
119
|
+
self.quantum_channel_list.append(quantum_channel_T)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def X_gate(self, idx, is_expectation = False, tag = "X gate"):
|
|
123
|
+
if self.backend == "statevector":
|
|
124
|
+
quantum_channel_X = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([idx], X(0).get_compact_qobj()), backend = self.backend, name = tag)
|
|
125
|
+
elif self.backend == "tensor":
|
|
126
|
+
dense_op = X(0).get_compact_qobj().full()
|
|
127
|
+
X_MPO = mpo.from_dense(dense_op, dims = 2, sites = (idx,), L=self.num_qubits, tags=tag)
|
|
128
|
+
quantum_channel_X = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = X_MPO, backend = self.backend, name = tag)
|
|
129
|
+
|
|
130
|
+
if is_expectation:
|
|
131
|
+
self.expectation_ops.append(quantum_channel_X)
|
|
132
|
+
else:
|
|
133
|
+
self.quantum_channel_list.append(quantum_channel_X)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def Z_gate(self, idx, is_expectation = False, tag = "X gate"):
|
|
137
|
+
if self.backend == 'statevector':
|
|
138
|
+
quantum_channel_Z = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = ([idx], Z(0).get_compact_qobj()), backend = self.backend, name = tag)
|
|
139
|
+
elif self.backend == 'tensor':
|
|
140
|
+
dense_op = Z(0).get_compact_qobj().full()
|
|
141
|
+
Z_MPO = mpo.from_dense(dense_op, dims = 2, sites = (idx,), L=self.num_qubits, tags=tag)
|
|
142
|
+
quantum_channel_Z = quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "closed", unitary_op = Z_MPO, backend = self.backend, name = tag)
|
|
143
|
+
|
|
144
|
+
if is_expectation:
|
|
145
|
+
self.expectation_ops.append(quantum_channel_Z)
|
|
146
|
+
else:
|
|
147
|
+
self.quantum_channel_list.append(quantum_channel_Z)
|
|
148
|
+
|
|
149
|
+
def amplitude_damping(self, noise_parameter, idx, tag = "amplitude_damping"):
|
|
150
|
+
qc = Circuit.generate_amplitude_damping_quantum_channel(self.num_qubits, self.backend, noise_parameter, idx, tag = tag)
|
|
151
|
+
self.quantum_channel_list.append(qc)
|
|
152
|
+
|
|
153
|
+
@lru_cache(maxsize=100)
|
|
154
|
+
@staticmethod
|
|
155
|
+
def generate_amplitude_damping_quantum_channel(num_qubits, backend, noise_parameter, idx, tag = "amplitude_damping"):
|
|
156
|
+
damping_channels = amplitude_damping(noise_parameter = noise_parameter)
|
|
157
|
+
return quantum_channel(N = 2, num_modes = num_qubits, formalism = "kraus", kraus_ops_tuple = ((idx,), damping_channels), backend = backend, name = tag)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def phase_damping(self, noise_parameter, idx, tag = "phase_damping"):
|
|
161
|
+
damping_channels = phase_damping(noise_parameter = noise_parameter)
|
|
162
|
+
self.quantum_channel_list.append(quantum_channel(N = 2, num_modes = self.num_qubits, formalism = "kraus", kraus_ops_tuple = ((idx,), damping_channels), backend = self.backend, name = tag))
|
|
163
|
+
|
|
164
|
+
def perform_trajectree_simulation(self, num_simulations, error_tolerance = 1e-12, verbose = False):
|
|
165
|
+
times = []
|
|
166
|
+
evs = []
|
|
167
|
+
for _ in range(num_simulations):
|
|
168
|
+
start = time.time()
|
|
169
|
+
evs.append(self.t_eval.perform_simulation(self.psi, error_tolerance, normalize = True))
|
|
170
|
+
|
|
171
|
+
time_taken = time.time() - start
|
|
172
|
+
# print("time taken:", time_taken)
|
|
173
|
+
if verbose:
|
|
174
|
+
print("time taken:", time_taken)
|
|
175
|
+
# if i in progress:
|
|
176
|
+
# print(f"Completed {progress.index(i)+1}0% of simulations")
|
|
177
|
+
times.append(time_taken)
|
|
178
|
+
# print("done with simulations")
|
|
179
|
+
|
|
180
|
+
return evs, times
|
|
181
|
+
|
|
182
|
+
def qiskit_to_trajectree(self, qc, noise_parameter):
|
|
183
|
+
self.__init__(qc.num_qubits, backend = self.backend)
|
|
184
|
+
|
|
185
|
+
for circuit_instr in qc.data:
|
|
186
|
+
instr = circuit_instr.operation
|
|
187
|
+
qargs = circuit_instr.qubits
|
|
188
|
+
cargs = circuit_instr.clbits
|
|
189
|
+
gate_name = instr.name
|
|
190
|
+
|
|
191
|
+
if gate_name == 'x':
|
|
192
|
+
self.X_gate(qargs[0]._index)
|
|
193
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
194
|
+
|
|
195
|
+
elif gate_name == 'h':
|
|
196
|
+
self.H_gate(qargs[0]._index)
|
|
197
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
198
|
+
|
|
199
|
+
elif gate_name == 's':
|
|
200
|
+
self.S_gate(qargs[0]._index)
|
|
201
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
202
|
+
|
|
203
|
+
elif gate_name == 't':
|
|
204
|
+
self.T_gate(qargs[0]._index)
|
|
205
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
206
|
+
|
|
207
|
+
elif gate_name == 'z':
|
|
208
|
+
self.Z_gate(qargs[0]._index)
|
|
209
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
210
|
+
|
|
211
|
+
elif gate_name == 'cx':
|
|
212
|
+
self.CNOT_gate(qargs[0]._index, qargs[1]._index)
|
|
213
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
214
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[1]._index)
|
|
215
|
+
|
|
216
|
+
elif gate_name == 'cz':
|
|
217
|
+
self.CZ_gate(qargs[0]._index, qargs[1]._index)
|
|
218
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
219
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[1]._index)
|
|
220
|
+
|
|
221
|
+
elif gate_name == 'ry':
|
|
222
|
+
self.RY_gate(instr.params[0], qargs[0]._index)
|
|
223
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
224
|
+
|
|
225
|
+
elif gate_name == 'rz':
|
|
226
|
+
self.RZ_gate(instr.params[0], qargs[0]._index)
|
|
227
|
+
self.amplitude_damping(noise_parameter=noise_parameter, idx = qargs[0]._index)
|
|
228
|
+
|
|
229
|
+
self.create_trajectree()
|
|
230
|
+
|
|
231
|
+
def expectation(self, ops):
|
|
232
|
+
for i in range(len(ops)):
|
|
233
|
+
if ops[i] == 'x':
|
|
234
|
+
self.X_gate(i, is_expectation = True)
|
|
235
|
+
|
|
236
|
+
elif ops[i] == 'h':
|
|
237
|
+
self.H_gate(i, is_expectation = True)
|
|
238
|
+
|
|
239
|
+
elif ops[i] == 's':
|
|
240
|
+
self.S_gate(i, is_expectation = True)
|
|
241
|
+
|
|
242
|
+
elif ops[i] == 't':
|
|
243
|
+
self.T_gate(i, is_expectation = True)
|
|
244
|
+
|
|
245
|
+
elif ops[i] == 'z':
|
|
246
|
+
self.Z_gate(i, is_expectation = True)
|
|
247
|
+
else:
|
|
248
|
+
continue
|
|
249
|
+
self.t_eval.observable_ops = self.expectation_ops
|
|
250
|
+
self.t_eval.calc_expectation = True
|
|
251
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from scipy import sparse as sp
|
|
2
|
+
from scipy.linalg import expm
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy import sqrt
|
|
6
|
+
import qutip as qt
|
|
7
|
+
from math import factorial
|
|
8
|
+
from functools import lru_cache
|
|
9
|
+
|
|
10
|
+
@lru_cache(maxsize=100)
|
|
11
|
+
def amplitude_damping(noise_parameter):
|
|
12
|
+
|
|
13
|
+
ops = []
|
|
14
|
+
ops.append(sp.csr_array([[1, 0], [0, sqrt(1 - noise_parameter)]]))
|
|
15
|
+
ops.append(sp.csr_array([[0, sqrt(noise_parameter)], [0, 0]]))
|
|
16
|
+
return ops
|
|
17
|
+
|
|
18
|
+
@lru_cache(maxsize=100)
|
|
19
|
+
def phase_damping(noise_parameter):
|
|
20
|
+
|
|
21
|
+
ops = []
|
|
22
|
+
ops.append(sp.csr_array([[1, 0], [0, sqrt(1 - noise_parameter)]]))
|
|
23
|
+
ops.append(sp.csr_array([[0, 0], [0, sqrt(noise_parameter)]]))
|
|
24
|
+
return ops
|
trajectree/sequence/swap.py
CHANGED
|
@@ -10,28 +10,33 @@ import time
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
import copy
|
|
12
12
|
|
|
13
|
-
def generate_swapping_circuit(N, num_modes, site_tags, bsm_det_effs, bsm_dark_counts_gain, bsm_measurements,
|
|
13
|
+
def generate_swapping_circuit(N, num_modes, site_tags, bsm_det_effs, bsm_dark_counts_gain, bsm_measurements, channel_loss, depolarizing_error = False, damping_error = True, error_tolerance=1e-10):
|
|
14
14
|
quantum_channel_list = []
|
|
15
15
|
|
|
16
16
|
# Amplitude damping due to fibers
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
quantum_channel_list.append(quantum_channel(N = N, num_modes =
|
|
20
|
-
|
|
17
|
+
|
|
18
|
+
phase_flip_ops = [sp.csr_matrix(global_phase(0, N, return_unitary = True, site1 = 0, site2 = 1, total_sites = 8))]
|
|
19
|
+
quantum_channel_list.append(quantum_channel(N = N, num_modes = 8, formalism = "kraus", kraus_ops_tuple = ((0,1), phase_flip_ops), name = "first_kraus"))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# damping_kraus_ops = single_mode_bosonic_noise_channels(noise_parameter = 1-1e-3, N = N)
|
|
23
|
+
# two_mode_kraus_ops = [[sp.kron(op1, op2) for op1 in damping_kraus_ops for op2 in damping_kraus_ops][0]]
|
|
24
|
+
# quantum_channel_list.append(quantum_channel(N = N, num_modes = num_modes, formalism = "kraus", kraus_ops_tuple = ((2,3), two_mode_kraus_ops), name = "fiber_attenuation")) # The tuples in this list are defined as (sites, kraus_ops). The sites are the sites where the Kraus ops are applied.
|
|
25
|
+
# quantum_channel_list.append(quantum_channel(N = N, num_modes = num_modes, formalism = "kraus", kraus_ops_tuple = ((6,7), two_mode_kraus_ops), name = "fiber_attenuation")) # The tuples in this list are defined as (sites, kraus_ops). The sites are the sites where the Kraus ops are applied.
|
|
21
26
|
|
|
22
27
|
# Quantum channel for the Bell state measurement
|
|
23
28
|
# BSM_MPOs = bell_state_measurement(None, N, site_tags, num_modes, bsm_det_effs, error_tolerance, measurements = bsm_measurements, pnr = False, use_trajectory = True, return_MPOs = True, compress=True, contract=True)
|
|
24
29
|
# BSM_quantum_channels = [quantum_channel(N = N, num_modes = num_modes, formalism = "closed", unitary_MPOs = BSM_MPO, name = "BSM") for BSM_MPO in BSM_MPOs]
|
|
25
|
-
|
|
30
|
+
|
|
31
|
+
BSM_quantum_channels, expectation_channels = bell_state_measurement(None, N, site_tags, num_modes, bsm_det_effs, bsm_dark_counts_gain, error_tolerance, measurements = bsm_measurements, depolarizing_error = depolarizing_error, damping_error = damping_error, pnr = False, use_trajectory = True, return_MPOs = True, compress=True, contract=True)
|
|
26
32
|
quantum_channel_list.extend(BSM_quantum_channels)
|
|
27
33
|
|
|
28
|
-
return quantum_channel_list
|
|
34
|
+
return quantum_channel_list, expectation_channels
|
|
29
35
|
|
|
30
|
-
def analyze_entanglement(quantum_channel_list, N, site_tags, num_modes, efficiency, error_tolerance, idler_angles, signal_angles):
|
|
31
|
-
|
|
32
|
-
PA_quantum_channels = [quantum_channel(N = N, num_modes = num_modes, formalism = "closed", unitary_MPOs = PA_MPO) for PA_MPO in PA_MPOs]
|
|
33
|
-
# print("num pa quantum channels:", len(PA_quantum_channels))
|
|
36
|
+
def analyze_entanglement(quantum_channel_list, expectation_channels, N, site_tags, num_modes, efficiency, error_tolerance, idler_angles, signal_angles, depolarizing_error = False, damping_error = True):
|
|
37
|
+
PA_quantum_channels, PA_expectation_channels = rotate_and_measure(None, N, site_tags, num_modes, efficiency, error_tolerance, idler_angles, signal_angles, depolarizing_error = depolarizing_error, damping_error = damping_error, return_quantum_channel = True)
|
|
34
38
|
quantum_channel_list.extend(PA_quantum_channels)
|
|
39
|
+
expectation_channels.extend(PA_expectation_channels)
|
|
35
40
|
|
|
36
41
|
|
|
37
42
|
def create_swapping_initial_state(num_modes, N, mean_photon_num, error_tolerance):
|
|
@@ -44,34 +49,53 @@ def create_swapping_initial_state(num_modes, N, mean_photon_num, error_tolerance
|
|
|
44
49
|
psi = extend_MPS(psi)
|
|
45
50
|
return psi
|
|
46
51
|
|
|
47
|
-
def
|
|
48
|
-
|
|
52
|
+
def create_swapping_simulation(N, num_modes, params, cache_size, error_tolerance = 1e-10):
|
|
49
53
|
psi = create_swapping_initial_state(num_modes, N, params["chi"], error_tolerance)
|
|
50
54
|
|
|
51
|
-
quantum_channels = generate_swapping_circuit(N, num_modes, psi.site_tags, [params["BSM_det_loss_1"], params["BSM_det_loss_2"]], [params["BSM_dark_counts_1"], params["BSM_dark_counts_2"]], params["BSM_meas"], params["channel_loss"], error_tolerance)
|
|
55
|
+
quantum_channels, expectation_channels = generate_swapping_circuit(N, num_modes, psi.site_tags, [params["BSM_det_loss_1"], params["BSM_det_loss_2"]], [params["BSM_dark_counts_1"], params["BSM_dark_counts_2"]], params["BSM_meas"], params["channel_loss"], depolarizing_error = params["depolarizing_error"], damping_error = params["damping_error"], error_tolerance = error_tolerance)
|
|
52
56
|
|
|
53
57
|
if params["if_analyze_entanglement"]:
|
|
54
|
-
analyze_entanglement(quantum_channels, N, psi.site_tags, num_modes, params["PA_det_eff"], error_tolerance, params["alpha_list"], params["delta_list"])
|
|
58
|
+
analyze_entanglement(quantum_channels, expectation_channels, N, psi.site_tags, num_modes, params["PA_det_eff"], error_tolerance, params["alpha_list"], params["delta_list"], depolarizing_error = params["depolarizing_error"], damping_error = params["damping_error"])
|
|
59
|
+
|
|
60
|
+
# quantum_channels.extend(expectation_channels)
|
|
55
61
|
|
|
56
|
-
t_eval = trajectory_evaluator(quantum_channels)
|
|
62
|
+
t_eval = trajectory_evaluator(quantum_channels, cache_size = cache_size, max_cache_nodes = params["max_cache_nodes"], calc_expectation = True, observable_ops = expectation_channels)
|
|
63
|
+
|
|
64
|
+
return psi, t_eval
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def perform_swapping_simulation(psi, t_eval, num_simulations, verbose = False, N = None, calc_fidelity = False, error_tolerance = 1e-10):
|
|
68
|
+
# print("initial state:")
|
|
69
|
+
# read_quantum_state(psi, N)
|
|
70
|
+
|
|
71
|
+
# phase_flip_ops = [sp.csr_matrix(global_phase(0, N, return_unitary = True, site1 = 0, site2 = 1, total_sites = 2))]
|
|
72
|
+
# quantum_channels.append(quantum_channel(N = N, num_modes = 8, formalism = "kraus", kraus_ops_tuple = ((0,1), phase_flip_ops), name = "first_kraus"))
|
|
57
73
|
|
|
58
74
|
fidelities = []
|
|
59
75
|
probabilities = []
|
|
76
|
+
times = []
|
|
77
|
+
progress = [x * num_simulations//10 for x in range(1, 11)]
|
|
60
78
|
|
|
61
79
|
for i in range(num_simulations):
|
|
62
80
|
start = time.time()
|
|
63
|
-
psi_iter =
|
|
81
|
+
psi_iter = probabilities.append(t_eval.perform_simulation(psi, error_tolerance, normalize = True))
|
|
64
82
|
|
|
65
|
-
|
|
83
|
+
# # read_quantum_state(psi_iter, N)
|
|
84
|
+
# if psi_iter == 0:
|
|
85
|
+
# probabilities.append(0)
|
|
86
|
+
# else:
|
|
87
|
+
# probabilities.append(psi_iter.normalize())
|
|
66
88
|
|
|
67
|
-
if
|
|
68
|
-
|
|
69
|
-
|
|
89
|
+
# if calc_fidelity:
|
|
90
|
+
# fidelity = np.abs(calc_fidelity_swapping(psi_iter, "psi_minus", N, error_tolerance))
|
|
91
|
+
# fidelities.append(fidelity)
|
|
70
92
|
|
|
71
93
|
time_taken = time.time() - start
|
|
72
|
-
|
|
94
|
+
if verbose:
|
|
95
|
+
if i in progress:
|
|
96
|
+
print(f"Completed {progress.index(i)+1}0% of simulations")
|
|
97
|
+
times.append(time_taken)
|
|
73
98
|
|
|
74
99
|
# print("completed set", "cache_hits:", t_eval.cache_hit, "cache_partial_hits:", t_eval.cache_partial_hit, "cache_misses:", t_eval.cache_miss, "time taken:", time_taken)
|
|
75
100
|
|
|
76
|
-
return fidelities, probabilities,
|
|
77
|
-
|
|
101
|
+
return fidelities, probabilities, times
|