pyGSTi 0.9.12__cp38-cp38-win32.whl → 0.9.13__cp38-cp38-win32.whl
Sign up to get free protection for your applications and to get access to all the features.
- pyGSTi-0.9.13.dist-info/METADATA +185 -0
- {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/RECORD +211 -220
- {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/WHEEL +1 -1
- pygsti/_version.py +2 -2
- pygsti/algorithms/contract.py +1 -1
- pygsti/algorithms/core.py +62 -35
- pygsti/algorithms/fiducialpairreduction.py +95 -110
- pygsti/algorithms/fiducialselection.py +17 -8
- pygsti/algorithms/gaugeopt.py +2 -2
- pygsti/algorithms/germselection.py +87 -77
- pygsti/algorithms/mirroring.py +0 -388
- pygsti/algorithms/randomcircuit.py +165 -1333
- pygsti/algorithms/rbfit.py +0 -234
- pygsti/baseobjs/basis.py +94 -396
- pygsti/baseobjs/errorgenbasis.py +0 -132
- pygsti/baseobjs/errorgenspace.py +0 -10
- pygsti/baseobjs/label.py +52 -168
- pygsti/baseobjs/opcalc/fastopcalc.cp38-win32.pyd +0 -0
- pygsti/baseobjs/opcalc/fastopcalc.pyx +2 -2
- pygsti/baseobjs/polynomial.py +13 -595
- pygsti/baseobjs/protectedarray.py +72 -132
- pygsti/baseobjs/statespace.py +1 -0
- pygsti/circuits/__init__.py +1 -1
- pygsti/circuits/circuit.py +753 -504
- pygsti/circuits/circuitconstruction.py +0 -4
- pygsti/circuits/circuitlist.py +47 -5
- pygsti/circuits/circuitparser/__init__.py +8 -8
- pygsti/circuits/circuitparser/fastcircuitparser.cp38-win32.pyd +0 -0
- pygsti/circuits/circuitstructure.py +3 -3
- pygsti/circuits/cloudcircuitconstruction.py +27 -14
- pygsti/data/datacomparator.py +4 -9
- pygsti/data/dataset.py +51 -46
- pygsti/data/hypothesistest.py +0 -7
- pygsti/drivers/bootstrap.py +0 -49
- pygsti/drivers/longsequence.py +46 -10
- pygsti/evotypes/basereps_cython.cp38-win32.pyd +0 -0
- pygsti/evotypes/chp/opreps.py +0 -61
- pygsti/evotypes/chp/statereps.py +0 -32
- pygsti/evotypes/densitymx/effectcreps.cpp +9 -10
- pygsti/evotypes/densitymx/effectreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/densitymx/effectreps.pyx +1 -1
- pygsti/evotypes/densitymx/opreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/densitymx/opreps.pyx +2 -2
- pygsti/evotypes/densitymx/statereps.cp38-win32.pyd +0 -0
- pygsti/evotypes/densitymx/statereps.pyx +1 -1
- pygsti/evotypes/densitymx_slow/effectreps.py +7 -23
- pygsti/evotypes/densitymx_slow/opreps.py +16 -23
- pygsti/evotypes/densitymx_slow/statereps.py +10 -3
- pygsti/evotypes/evotype.py +39 -2
- pygsti/evotypes/stabilizer/effectreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/stabilizer/effectreps.pyx +0 -4
- pygsti/evotypes/stabilizer/opreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/stabilizer/opreps.pyx +0 -4
- pygsti/evotypes/stabilizer/statereps.cp38-win32.pyd +0 -0
- pygsti/evotypes/stabilizer/statereps.pyx +1 -5
- pygsti/evotypes/stabilizer/termreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/stabilizer/termreps.pyx +0 -7
- pygsti/evotypes/stabilizer_slow/effectreps.py +0 -22
- pygsti/evotypes/stabilizer_slow/opreps.py +0 -4
- pygsti/evotypes/stabilizer_slow/statereps.py +0 -4
- pygsti/evotypes/statevec/effectreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/statevec/effectreps.pyx +1 -1
- pygsti/evotypes/statevec/opreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/statevec/opreps.pyx +2 -2
- pygsti/evotypes/statevec/statereps.cp38-win32.pyd +0 -0
- pygsti/evotypes/statevec/statereps.pyx +1 -1
- pygsti/evotypes/statevec/termreps.cp38-win32.pyd +0 -0
- pygsti/evotypes/statevec/termreps.pyx +0 -7
- pygsti/evotypes/statevec_slow/effectreps.py +0 -3
- pygsti/evotypes/statevec_slow/opreps.py +0 -5
- pygsti/extras/__init__.py +0 -1
- pygsti/extras/drift/signal.py +1 -1
- pygsti/extras/drift/stabilityanalyzer.py +3 -1
- pygsti/extras/interpygate/__init__.py +12 -0
- pygsti/extras/interpygate/core.py +0 -36
- pygsti/extras/interpygate/process_tomography.py +44 -10
- pygsti/extras/rpe/rpeconstruction.py +0 -2
- pygsti/forwardsims/__init__.py +1 -0
- pygsti/forwardsims/forwardsim.py +50 -93
- pygsti/forwardsims/mapforwardsim.py +78 -20
- pygsti/forwardsims/mapforwardsim_calc_densitymx.cp38-win32.pyd +0 -0
- pygsti/forwardsims/mapforwardsim_calc_densitymx.pyx +65 -66
- pygsti/forwardsims/mapforwardsim_calc_generic.py +91 -13
- pygsti/forwardsims/matrixforwardsim.py +72 -17
- pygsti/forwardsims/termforwardsim.py +9 -111
- pygsti/forwardsims/termforwardsim_calc_stabilizer.cp38-win32.pyd +0 -0
- pygsti/forwardsims/termforwardsim_calc_statevec.cp38-win32.pyd +0 -0
- pygsti/forwardsims/termforwardsim_calc_statevec.pyx +0 -651
- pygsti/forwardsims/torchfwdsim.py +265 -0
- pygsti/forwardsims/weakforwardsim.py +2 -2
- pygsti/io/__init__.py +1 -2
- pygsti/io/mongodb.py +0 -2
- pygsti/io/stdinput.py +6 -22
- pygsti/layouts/copalayout.py +10 -12
- pygsti/layouts/distlayout.py +0 -40
- pygsti/layouts/maplayout.py +103 -25
- pygsti/layouts/matrixlayout.py +99 -60
- pygsti/layouts/prefixtable.py +1534 -52
- pygsti/layouts/termlayout.py +1 -1
- pygsti/modelmembers/instruments/instrument.py +3 -3
- pygsti/modelmembers/instruments/tpinstrument.py +2 -2
- pygsti/modelmembers/modelmember.py +0 -17
- pygsti/modelmembers/operations/__init__.py +3 -4
- pygsti/modelmembers/operations/affineshiftop.py +206 -0
- pygsti/modelmembers/operations/composederrorgen.py +1 -1
- pygsti/modelmembers/operations/composedop.py +1 -24
- pygsti/modelmembers/operations/denseop.py +5 -5
- pygsti/modelmembers/operations/eigpdenseop.py +2 -2
- pygsti/modelmembers/operations/embeddederrorgen.py +1 -1
- pygsti/modelmembers/operations/embeddedop.py +0 -1
- pygsti/modelmembers/operations/experrorgenop.py +5 -2
- pygsti/modelmembers/operations/fullarbitraryop.py +1 -0
- pygsti/modelmembers/operations/fullcptpop.py +2 -2
- pygsti/modelmembers/operations/fulltpop.py +28 -6
- pygsti/modelmembers/operations/fullunitaryop.py +5 -4
- pygsti/modelmembers/operations/lindbladcoefficients.py +93 -78
- pygsti/modelmembers/operations/lindbladerrorgen.py +268 -441
- pygsti/modelmembers/operations/linearop.py +7 -27
- pygsti/modelmembers/operations/opfactory.py +1 -1
- pygsti/modelmembers/operations/repeatedop.py +1 -24
- pygsti/modelmembers/operations/staticstdop.py +1 -1
- pygsti/modelmembers/povms/__init__.py +3 -3
- pygsti/modelmembers/povms/basepovm.py +7 -36
- pygsti/modelmembers/povms/complementeffect.py +4 -9
- pygsti/modelmembers/povms/composedeffect.py +0 -320
- pygsti/modelmembers/povms/computationaleffect.py +1 -1
- pygsti/modelmembers/povms/computationalpovm.py +3 -1
- pygsti/modelmembers/povms/effect.py +3 -5
- pygsti/modelmembers/povms/marginalizedpovm.py +3 -81
- pygsti/modelmembers/povms/tppovm.py +74 -2
- pygsti/modelmembers/states/__init__.py +2 -5
- pygsti/modelmembers/states/composedstate.py +0 -317
- pygsti/modelmembers/states/computationalstate.py +3 -3
- pygsti/modelmembers/states/cptpstate.py +4 -4
- pygsti/modelmembers/states/densestate.py +10 -8
- pygsti/modelmembers/states/fullpurestate.py +0 -24
- pygsti/modelmembers/states/purestate.py +1 -1
- pygsti/modelmembers/states/state.py +5 -6
- pygsti/modelmembers/states/tpstate.py +28 -10
- pygsti/modelmembers/term.py +3 -6
- pygsti/modelmembers/torchable.py +50 -0
- pygsti/modelpacks/_modelpack.py +1 -1
- pygsti/modelpacks/smq1Q_ZN.py +3 -1
- pygsti/modelpacks/smq2Q_XXYYII.py +2 -1
- pygsti/modelpacks/smq2Q_XY.py +3 -3
- pygsti/modelpacks/smq2Q_XYI.py +2 -2
- pygsti/modelpacks/smq2Q_XYICNOT.py +3 -3
- pygsti/modelpacks/smq2Q_XYICPHASE.py +3 -3
- pygsti/modelpacks/smq2Q_XYXX.py +1 -1
- pygsti/modelpacks/smq2Q_XYZICNOT.py +3 -3
- pygsti/modelpacks/smq2Q_XYZZ.py +1 -1
- pygsti/modelpacks/stdtarget.py +0 -121
- pygsti/models/cloudnoisemodel.py +1 -2
- pygsti/models/explicitcalc.py +3 -3
- pygsti/models/explicitmodel.py +3 -13
- pygsti/models/fogistore.py +5 -3
- pygsti/models/localnoisemodel.py +1 -2
- pygsti/models/memberdict.py +0 -12
- pygsti/models/model.py +801 -68
- pygsti/models/modelconstruction.py +4 -4
- pygsti/models/modelnoise.py +2 -2
- pygsti/models/modelparaminterposer.py +1 -1
- pygsti/models/oplessmodel.py +1 -1
- pygsti/models/qutrit.py +15 -14
- pygsti/objectivefns/objectivefns.py +75 -140
- pygsti/objectivefns/wildcardbudget.py +2 -7
- pygsti/optimize/__init__.py +1 -0
- pygsti/optimize/arraysinterface.py +28 -0
- pygsti/optimize/customcg.py +0 -12
- pygsti/optimize/customlm.py +129 -323
- pygsti/optimize/customsolve.py +2 -2
- pygsti/optimize/optimize.py +0 -84
- pygsti/optimize/simplerlm.py +841 -0
- pygsti/optimize/wildcardopt.py +19 -598
- pygsti/protocols/confidenceregionfactory.py +28 -14
- pygsti/protocols/estimate.py +31 -14
- pygsti/protocols/gst.py +238 -142
- pygsti/protocols/modeltest.py +19 -12
- pygsti/protocols/protocol.py +9 -37
- pygsti/protocols/rb.py +450 -79
- pygsti/protocols/treenode.py +8 -2
- pygsti/protocols/vb.py +108 -206
- pygsti/protocols/vbdataframe.py +1 -1
- pygsti/report/factory.py +0 -15
- pygsti/report/fogidiagram.py +1 -17
- pygsti/report/modelfunction.py +12 -3
- pygsti/report/mpl_colormaps.py +1 -1
- pygsti/report/plothelpers.py +11 -3
- pygsti/report/report.py +16 -0
- pygsti/report/reportables.py +41 -37
- pygsti/report/templates/offline/pygsti_dashboard.css +6 -0
- pygsti/report/templates/offline/pygsti_dashboard.js +12 -0
- pygsti/report/workspace.py +2 -14
- pygsti/report/workspaceplots.py +328 -505
- pygsti/tools/basistools.py +9 -36
- pygsti/tools/edesigntools.py +124 -96
- pygsti/tools/fastcalc.cp38-win32.pyd +0 -0
- pygsti/tools/fastcalc.pyx +35 -81
- pygsti/tools/internalgates.py +151 -15
- pygsti/tools/jamiolkowski.py +5 -5
- pygsti/tools/lindbladtools.py +19 -11
- pygsti/tools/listtools.py +0 -114
- pygsti/tools/matrixmod2.py +1 -1
- pygsti/tools/matrixtools.py +173 -339
- pygsti/tools/nameddict.py +1 -1
- pygsti/tools/optools.py +154 -88
- pygsti/tools/pdftools.py +0 -25
- pygsti/tools/rbtheory.py +3 -320
- pygsti/tools/slicetools.py +64 -12
- pyGSTi-0.9.12.dist-info/METADATA +0 -157
- pygsti/algorithms/directx.py +0 -711
- pygsti/evotypes/qibo/__init__.py +0 -33
- pygsti/evotypes/qibo/effectreps.py +0 -78
- pygsti/evotypes/qibo/opreps.py +0 -376
- pygsti/evotypes/qibo/povmreps.py +0 -98
- pygsti/evotypes/qibo/statereps.py +0 -174
- pygsti/extras/rb/__init__.py +0 -13
- pygsti/extras/rb/benchmarker.py +0 -957
- pygsti/extras/rb/dataset.py +0 -378
- pygsti/extras/rb/io.py +0 -814
- pygsti/extras/rb/simulate.py +0 -1020
- pygsti/io/legacyio.py +0 -385
- pygsti/modelmembers/povms/denseeffect.py +0 -142
- {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/LICENSE +0 -0
- {pyGSTi-0.9.12.dist-info → pyGSTi-0.9.13.dist-info}/top_level.txt +0 -0
pygsti/tools/matrixtools.py
CHANGED
@@ -30,36 +30,38 @@ except ImportError:
|
|
30
30
|
#EXPM_DEFAULT_TOL = 1e-7
|
31
31
|
EXPM_DEFAULT_TOL = 2**-53 # Scipy default
|
32
32
|
|
33
|
+
BLAS_FUNCS = {
|
34
|
+
'herk': {
|
35
|
+
's' : _spl.blas.ssyrk,
|
36
|
+
'd' : _spl.blas.dsyrk,
|
37
|
+
'c' : _spl.blas.cherk,
|
38
|
+
'z': _spl.blas.zherk
|
39
|
+
}
|
40
|
+
}
|
33
41
|
|
34
|
-
def
|
42
|
+
def gram_matrix(m, adjoint=False):
|
35
43
|
"""
|
36
|
-
|
44
|
+
If adjoint=False, then return m.T.conj() @ m, computed in a more efficient way.
|
37
45
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
----------
|
44
|
-
m : numpy array
|
45
|
-
the matrix (any object that can be double-indexed)
|
46
|
+
If adjoint=True, return m @ m.T.conj(), likewise computed in a more efficient way.
|
47
|
+
"""
|
48
|
+
assert isinstance(m, _np.ndarray)
|
49
|
+
prefix_char, _, _ = _spl.blas.find_best_blas_type(dtype=m.dtype)
|
50
|
+
herk = BLAS_FUNCS["herk"][prefix_char]
|
46
51
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# print M[i,i]
|
61
|
-
# raise ValueError("STOP")
|
62
|
-
# return ret
|
52
|
+
if adjoint:
|
53
|
+
trans = 0
|
54
|
+
elif _np.iscomplexobj(m):
|
55
|
+
trans = 2
|
56
|
+
else:
|
57
|
+
trans = 1
|
58
|
+
out = herk(1.0, m, trans=trans)
|
59
|
+
i_lower = _np.tril_indices(out.shape[0], -1)
|
60
|
+
upper_values = out.T[i_lower]
|
61
|
+
out[i_lower] = upper_values.real
|
62
|
+
if trans > 0:
|
63
|
+
out[i_lower] += upper_values.imag
|
64
|
+
return out
|
63
65
|
|
64
66
|
|
65
67
|
def is_hermitian(mx, tol=1e-9):
|
@@ -80,14 +82,13 @@ def is_hermitian(mx, tol=1e-9):
|
|
80
82
|
True if mx is hermitian, otherwise False.
|
81
83
|
"""
|
82
84
|
(m, n) = mx.shape
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
return True
|
85
|
+
if m != n:
|
86
|
+
return False
|
87
|
+
else:
|
88
|
+
return _np.all(_np.abs(mx - mx.T.conj()) <= tol)
|
88
89
|
|
89
90
|
|
90
|
-
def is_pos_def(mx, tol=1e-9):
|
91
|
+
def is_pos_def(mx, tol=1e-9, attempt_cholesky=False):
|
91
92
|
"""
|
92
93
|
Test whether mx is a positive-definite matrix.
|
93
94
|
|
@@ -104,7 +105,15 @@ def is_pos_def(mx, tol=1e-9):
|
|
104
105
|
bool
|
105
106
|
True if mx is positive-semidefinite, otherwise False.
|
106
107
|
"""
|
107
|
-
|
108
|
+
if not is_hermitian(mx, tol):
|
109
|
+
return False
|
110
|
+
if attempt_cholesky:
|
111
|
+
try:
|
112
|
+
_ = _spl.cholesky(mx)
|
113
|
+
return True # Cholesky succeeded
|
114
|
+
except _spl.LinAlgError:
|
115
|
+
pass # we fall back on eigenvalue decomposition
|
116
|
+
evals = _np.linalg.eigvalsh(mx)
|
108
117
|
return all([ev > -tol for ev in evals])
|
109
118
|
|
110
119
|
|
@@ -125,47 +134,8 @@ def is_valid_density_mx(mx, tol=1e-9):
|
|
125
134
|
bool
|
126
135
|
True if mx is a valid density matrix, otherwise False.
|
127
136
|
"""
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
def frobeniusnorm(ar):
|
132
|
-
"""
|
133
|
-
Compute the frobenius norm of an array (or matrix),
|
134
|
-
|
135
|
-
sqrt( sum( each_element_of_a^2 ) )
|
136
|
-
|
137
|
-
Parameters
|
138
|
-
----------
|
139
|
-
ar : numpy array
|
140
|
-
What to compute the frobenius norm of. Note that ar can be any shape
|
141
|
-
or number of dimenions.
|
142
|
-
|
143
|
-
Returns
|
144
|
-
-------
|
145
|
-
float or complex
|
146
|
-
depending on the element type of ar.
|
147
|
-
"""
|
148
|
-
return _np.sqrt(_np.sum(ar**2))
|
149
|
-
|
150
|
-
|
151
|
-
def frobeniusnorm_squared(ar):
|
152
|
-
"""
|
153
|
-
Compute the squared frobenius norm of an array (or matrix),
|
154
|
-
|
155
|
-
sum( each_element_of_a^2 ) )
|
156
|
-
|
157
|
-
Parameters
|
158
|
-
----------
|
159
|
-
ar : numpy array
|
160
|
-
What to compute the squared frobenius norm of. Note that ar can be any
|
161
|
-
shape or number of dimenions.
|
162
|
-
|
163
|
-
Returns
|
164
|
-
-------
|
165
|
-
float or complex
|
166
|
-
depending on the element type of ar.
|
167
|
-
"""
|
168
|
-
return _np.sum(ar**2)
|
137
|
+
# is_pos_def includes a check that the matrix is Hermitian.
|
138
|
+
return abs(_np.trace(mx) - 1.0) < tol and is_pos_def(mx, tol)
|
169
139
|
|
170
140
|
|
171
141
|
def nullspace(m, tol=1e-7):
|
@@ -186,7 +156,7 @@ def nullspace(m, tol=1e-7):
|
|
186
156
|
"""
|
187
157
|
_, s, vh = _np.linalg.svd(m)
|
188
158
|
rank = (s > tol).sum()
|
189
|
-
return vh[rank:].T.conjugate()
|
159
|
+
return vh[rank:].T.conjugate()
|
190
160
|
|
191
161
|
|
192
162
|
def nullspace_qr(m, tol=1e-7):
|
@@ -227,10 +197,7 @@ def nice_nullspace(m, tol=1e-7, orthogonalize=False):
|
|
227
197
|
Computes the nullspace of a matrix, and tries to return a "nice" basis for it.
|
228
198
|
|
229
199
|
Columns of the returned value (a basis for the nullspace) each have a maximum
|
230
|
-
absolute value of 1.0
|
231
|
-
matrix's basis as much as possible (the basis is found by projecting each
|
232
|
-
original basis vector onto an arbitrariliy-found nullspace and keeping only
|
233
|
-
a set of linearly independent projections).
|
200
|
+
absolute value of 1.0.
|
234
201
|
|
235
202
|
Parameters
|
236
203
|
----------
|
@@ -248,21 +215,22 @@ def nice_nullspace(m, tol=1e-7, orthogonalize=False):
|
|
248
215
|
An matrix of shape (M,K) whose columns contain nullspace basis vectors.
|
249
216
|
"""
|
250
217
|
nullsp = nullspace(m, tol)
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
218
|
+
dim_ker = nullsp.shape[1]
|
219
|
+
if dim_ker == 0:
|
220
|
+
return nullsp # empty 0-by-N array
|
221
|
+
_, _, p = _spl.qr(nullsp.T.conj(), mode='raw', pivoting=True)
|
222
|
+
ret = nullsp @ (nullsp.T[:, p[:dim_ker]]).conj()
|
223
|
+
# ^ That's equivalent to, but faster than:
|
224
|
+
# nullsp_projector = nullsp @ nullsp.T.conj()
|
225
|
+
# _, _, p = _spl.qr(nullsp_projector mode='raw', pivoting=True)
|
226
|
+
# ret = nullsp_projector[:, p[:dim_ker]]
|
227
|
+
|
228
|
+
if orthogonalize:
|
229
|
+
ret, _ = _spl.qr(ret, mode='economic')
|
263
230
|
for j in range(ret.shape[1]): # normalize columns so largest element is +1.0
|
264
231
|
imax = _np.argmax(_np.abs(ret[:, j]))
|
265
|
-
if abs(ret[imax, j]) > 1e-6:
|
232
|
+
if abs(ret[imax, j]) > 1e-6:
|
233
|
+
ret[:, j] /= ret[imax, j]
|
266
234
|
|
267
235
|
return ret
|
268
236
|
|
@@ -319,14 +287,16 @@ def column_norms(m, ord=None):
|
|
319
287
|
numpy.ndarray
|
320
288
|
A 1-dimensional array of the column norms (length is number of columns of `m`).
|
321
289
|
"""
|
322
|
-
ord_list = [ord] * m.shape[1] if (ord is None or isinstance(ord, int)) else ord
|
323
|
-
assert(len(ord_list) == m.shape[1])
|
324
|
-
|
325
290
|
if _sps.issparse(m):
|
326
|
-
|
291
|
+
ord_list = ord if isinstance(ord, (list, _np.ndarray)) else [ord] * m.shape[1]
|
292
|
+
assert(len(ord_list) == m.shape[1])
|
327
293
|
norms = _np.array([_np.linalg.norm(m[:, j].toarray(), ord=o) for j, o in enumerate(ord_list)])
|
294
|
+
elif isinstance(ord, (list, _np.ndarray)):
|
295
|
+
assert(len(ord) == m.shape[1])
|
296
|
+
norms = _np.array([_np.linalg.norm(m[:, j], ord=o) for j, o in enumerate(ord)])
|
328
297
|
else:
|
329
|
-
norms = _np.
|
298
|
+
norms = _np.linalg.norm(m, axis=0, ord=ord)
|
299
|
+
|
330
300
|
return norms
|
331
301
|
|
332
302
|
|
@@ -382,8 +352,9 @@ def columns_are_orthogonal(m, tol=1e-7):
|
|
382
352
|
-------
|
383
353
|
bool
|
384
354
|
"""
|
385
|
-
if m.size == 0:
|
386
|
-
|
355
|
+
if m.size == 0:
|
356
|
+
return True # boundary case
|
357
|
+
check = gram_matrix(m)
|
387
358
|
check[_np.diag_indices_from(check)] = 0.0
|
388
359
|
return bool(_np.linalg.norm(check) / check.size < tol)
|
389
360
|
|
@@ -408,9 +379,11 @@ def columns_are_orthonormal(m, tol=1e-7):
|
|
408
379
|
-------
|
409
380
|
bool
|
410
381
|
"""
|
411
|
-
if m.size == 0:
|
412
|
-
|
413
|
-
|
382
|
+
if m.size == 0:
|
383
|
+
return True # boundary case
|
384
|
+
check = gram_matrix(m)
|
385
|
+
check[_np.diag_indices_from(check)] -= 1.0
|
386
|
+
return bool(_np.linalg.norm(check) / check.size < tol)
|
414
387
|
|
415
388
|
|
416
389
|
def independent_columns(m, initial_independent_cols=None, tol=1e-7):
|
@@ -440,27 +413,30 @@ def independent_columns(m, initial_independent_cols=None, tol=1e-7):
|
|
440
413
|
list
|
441
414
|
A list of the independent-column indices of `m`.
|
442
415
|
"""
|
443
|
-
indep_cols = []
|
444
|
-
|
445
416
|
if not _sps.issparse(m):
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
417
|
+
if initial_independent_cols is None:
|
418
|
+
proj_m = m.copy()
|
419
|
+
else:
|
420
|
+
# We assume initial_independent_cols is full column-rank.
|
421
|
+
# This lets us use unpivoted QR instead of pivoted QR or SVD.
|
422
|
+
assert initial_independent_cols.shape[0] == m.shape[0]
|
423
|
+
q = _spl.qr(initial_independent_cols, mode='econ')[0]
|
424
|
+
# proj_m = (I - qq')m
|
425
|
+
temp1 = q.T.conj() @ m
|
426
|
+
temp2 = q @ temp1
|
427
|
+
proj_m = m - temp2
|
428
|
+
|
429
|
+
rank = _np.linalg.matrix_rank(proj_m, tol=tol)
|
430
|
+
pivots = _spl.qr(proj_m, overwrite_a=True, mode='raw', pivoting=True)[2]
|
431
|
+
indep_cols = pivots[:rank].tolist()
|
458
432
|
|
433
|
+
else:
|
434
|
+
# TODO: re-implement to avoid unreliable calls to ARPACK's svds.
|
435
|
+
indep_cols = []
|
459
436
|
from scipy.sparse.linalg import ArpackNoConvergence as _ArpackNoConvergence
|
460
437
|
from scipy.sparse.linalg import ArpackError as _ArpackError
|
461
438
|
running_indep_cols = initial_independent_cols.copy() \
|
462
439
|
if (initial_independent_cols is not None) else _sps.csc_matrix((m.shape[0], 0), dtype=m.dtype)
|
463
|
-
num_indep_cols = running_indep_cols.shape[0]
|
464
440
|
|
465
441
|
for j in range(m.shape[1]):
|
466
442
|
trial = _sps.hstack((running_indep_cols, m[:, j]))
|
@@ -479,15 +455,33 @@ def independent_columns(m, initial_independent_cols=None, tol=1e-7):
|
|
479
455
|
|
480
456
|
|
481
457
|
def pinv_of_matrix_with_orthogonal_columns(m):
|
482
|
-
"""
|
483
|
-
|
458
|
+
"""
|
459
|
+
Return the matrix "pinv_m" so m @ pinvm and pinv_m @ m are orthogonal projectors
|
460
|
+
onto subspaces of dimension rank(m).
|
461
|
+
|
462
|
+
Parameters
|
463
|
+
----------
|
464
|
+
m : numpy.ndarray
|
465
|
+
|
466
|
+
Returns
|
467
|
+
----------
|
468
|
+
pinv_m : numpy.ndarray
|
469
|
+
"""
|
470
|
+
col_scaling = _np.linalg.norm(m, axis=0)**2
|
484
471
|
m_with_scaled_cols = m.conj() * col_scaling[None, :]
|
485
472
|
return m_with_scaled_cols.T
|
486
473
|
|
487
474
|
|
488
475
|
def matrix_sign(m):
|
489
476
|
"""
|
490
|
-
|
477
|
+
Compute the matrix s = sign(m). The eigenvectors of s are the same as those of m.
|
478
|
+
The eigenvalues of s are +/- 1, corresponding to the signs of m's eigenvalues.
|
479
|
+
|
480
|
+
It's straightforward to compute s when m is a normal operator. If m is not normal,
|
481
|
+
then the definition of s can be given in terms of m's Jordan form, and s
|
482
|
+
can be computed by (suitably post-processing) the Schur decomposition of m.
|
483
|
+
|
484
|
+
See https://nhigham.com/2020/12/15/what-is-the-matrix-sign-function/ for background.
|
491
485
|
|
492
486
|
Parameters
|
493
487
|
----------
|
@@ -498,40 +492,45 @@ def matrix_sign(m):
|
|
498
492
|
-------
|
499
493
|
numpy.ndarray
|
500
494
|
"""
|
501
|
-
|
502
|
-
|
495
|
+
N = m.shape[0]
|
496
|
+
assert(m.shape == (N, N)), "m must be square!"
|
503
497
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
U = _np.zeros(T.shape, 'complex') # will be sign(T), which is easy to compute
|
509
|
-
# (U is also upper triangular), and then sign(m) = Z U Z^H
|
498
|
+
if is_hermitian(m):
|
499
|
+
eigvals, eigvecs = _spl.eigh(m)
|
500
|
+
sign = (eigvecs * _np.sign(eigvals)[None, :]) @ eigvecs.T.conj()
|
501
|
+
return sign
|
510
502
|
|
511
|
-
#
|
503
|
+
T, Z = _spl.schur(m, 'complex') # m = Z T Z^H where Z is unitary and T is upper-triangular
|
504
|
+
U = _np.zeros(T.shape, 'complex')
|
512
505
|
U[_np.diag_indices_from(U)] = _np.sign(_np.diagonal(T))
|
506
|
+
# If T is diagonal, then we're basically done. If T isn't diagonal, then we have work to do.
|
507
|
+
|
508
|
+
if not _np.all(_np.isclose(T[_np.triu_indices(N, 1)], 0.0)):
|
509
|
+
# Use the extremely numerically stable (but expensive) method from
|
510
|
+
# N. Higham's book, Functions of Matrices : Theory and Practice, Chapter 5.
|
511
|
+
|
512
|
+
#Off diagonals: use U^2 = I or TU = UT
|
513
|
+
# Note: Tij = Uij = 0 when i > j and i==j easy so just consider i<j case
|
514
|
+
# 0 = sum_k Uik Ukj = (i!=j b/c off-diag)
|
515
|
+
# FUTURE: speed this up by using np.dot instead of sums below
|
516
|
+
for j in range(1, N):
|
517
|
+
for i in range(j - 1, -1, -1):
|
518
|
+
S = U[i, i] + U[j, j]
|
519
|
+
if _np.isclose(S, 0): # then use TU = UT
|
520
|
+
if _np.isclose(T[i, i] - T[j, j], 0): # then just set to zero
|
521
|
+
U[i, j] = 0.0 # TODO: check correctness of this case
|
522
|
+
else:
|
523
|
+
U[i, j] = T[i, j] * (U[i, i] - U[j, j]) / (T[i, i] - T[j, j]) + \
|
524
|
+
sum([U[i, k] * T[k, j] - T[i, k] * U[k, j] for k in range(i + 1, j)]) \
|
525
|
+
/ (T[i, i] - T[j, j])
|
526
|
+
else: # use U^2 = I
|
527
|
+
U[i, j] = - sum([U[i, k] * U[k, j] for k in range(i + 1, j)]) / S
|
528
|
+
else:
|
529
|
+
pass
|
513
530
|
|
514
|
-
|
515
|
-
|
516
|
-
# 0 = sum_k Uik Ukj = (i!=j b/c off-diag)
|
517
|
-
# FUTURE: speed this up by using np.dot instead of sums below
|
518
|
-
for j in range(1, N):
|
519
|
-
for i in range(j - 1, -1, -1):
|
520
|
-
S = U[i, i] + U[j, j]
|
521
|
-
if _np.isclose(S, 0): # then use TU = UT
|
522
|
-
if _np.isclose(T[i, i] - T[j, j], 0): # then just set to zero
|
523
|
-
U[i, j] = 0.0 # TODO: check correctness of this case
|
524
|
-
else:
|
525
|
-
U[i, j] = T[i, j] * (U[i, i] - U[j, j]) / (T[i, i] - T[j, j]) + \
|
526
|
-
sum([U[i, k] * T[k, j] - T[i, k] * U[k, j] for k in range(i + 1, j)]) \
|
527
|
-
/ (T[i, i] - T[j, j])
|
528
|
-
else: # use U^2 = I
|
529
|
-
U[i, j] = - sum([U[i, k] * U[k, j] for k in range(i + 1, j)]) / S
|
530
|
-
return _np.dot(Z, _np.dot(U, _np.conjugate(Z.T)))
|
531
|
+
sign = Z @ (U @ Z.T.conj())
|
532
|
+
return sign
|
531
533
|
|
532
|
-
#Quick & dirty - not always stable:
|
533
|
-
#U,_,Vt = _np.linalg.svd(M)
|
534
|
-
#return _np.dot(U,Vt)
|
535
534
|
|
536
535
|
|
537
536
|
def print_mx(mx, width=9, prec=4, withbrackets=False):
|
@@ -676,6 +675,7 @@ def unitary_superoperator_matrix_log(m, mx_basis):
|
|
676
675
|
evals = _np.linalg.eigvals(M_std)
|
677
676
|
assert(_np.allclose(_np.abs(evals), 1.0)) # simple but technically incomplete check for a unitary superop
|
678
677
|
# (e.g. could be anti-unitary: diag(1, -1, -1, -1))
|
678
|
+
|
679
679
|
U = _ot.std_process_mx_to_unitary(M_std)
|
680
680
|
H = _spl.logm(U) / -1j # U = exp(-iH)
|
681
681
|
logM_std = _lt.create_elementary_errorgen('H', H) # rho --> -i[H, rho]
|
@@ -757,7 +757,7 @@ def approximate_matrix_log(m, target_logm, target_weight=10.0, tol=1e-6):
|
|
757
757
|
logM = flat_logm.reshape(mx_shape)
|
758
758
|
testM = _spl.expm(logM)
|
759
759
|
ret = target_weight * _np.linalg.norm(logM - target_logm)**2 + \
|
760
|
-
_np.linalg.norm(testM.
|
760
|
+
_np.linalg.norm(testM.ravel() - m.ravel(), 1)
|
761
761
|
#print("DEBUG: ",ret)
|
762
762
|
return ret
|
763
763
|
|
@@ -774,7 +774,7 @@ def approximate_matrix_log(m, target_logm, target_weight=10.0, tol=1e-6):
|
|
774
774
|
print_obj_func = None
|
775
775
|
|
776
776
|
logM = _np.real(real_matrix_log(m, action_if_imaginary="ignore")) # just drop any imaginary part
|
777
|
-
initial_flat_logM = logM.
|
777
|
+
initial_flat_logM = logM.ravel() # + 0.1*target_logm.flatten()
|
778
778
|
# Note: adding some of target_logm doesn't seem to help; and hurts in easy cases
|
779
779
|
|
780
780
|
if _objective(initial_flat_logM) > 1e-16: # otherwise initial logM is fine!
|
@@ -902,9 +902,6 @@ def real_matrix_log(m, action_if_imaginary="raise", tol=1e-8):
|
|
902
902
|
|
903
903
|
|
904
904
|
## ------------------------ Erik : Matrix tools that Tim has moved here -----------
|
905
|
-
from scipy.linalg import sqrtm as _sqrtm
|
906
|
-
import itertools as _ittls
|
907
|
-
|
908
905
|
|
909
906
|
def column_basis_vector(i, dim):
|
910
907
|
"""
|
@@ -944,27 +941,9 @@ def vec(matrix_in):
|
|
944
941
|
return [b for a in _np.transpose(matrix_in) for b in a]
|
945
942
|
|
946
943
|
|
947
|
-
def unvec(vector_in):
|
948
|
-
"""
|
949
|
-
Slices a vector into the columns of a matrix.
|
950
|
-
|
951
|
-
Parameters
|
952
|
-
----------
|
953
|
-
vector_in : numpy.ndarray
|
954
|
-
|
955
|
-
Returns
|
956
|
-
-------
|
957
|
-
numpy.ndarray
|
958
|
-
"""
|
959
|
-
dim = int(_np.sqrt(len(vector_in)))
|
960
|
-
return _np.transpose(_np.array(list(
|
961
|
-
zip(*[_ittls.chain(vector_in,
|
962
|
-
_ittls.repeat(None, dim - 1))] * dim))))
|
963
|
-
|
964
|
-
|
965
944
|
def norm1(m):
|
966
945
|
"""
|
967
|
-
Returns the 1
|
946
|
+
Returns the Schatten 1-norm of a matrix
|
968
947
|
|
969
948
|
Parameters
|
970
949
|
----------
|
@@ -975,9 +954,13 @@ def norm1(m):
|
|
975
954
|
-------
|
976
955
|
numpy.ndarray
|
977
956
|
"""
|
978
|
-
|
957
|
+
s = _spl.svdvals(m)
|
958
|
+
nrm = _np.sum(s)
|
959
|
+
return nrm
|
979
960
|
|
980
961
|
|
962
|
+
# Riley note: I'd like to rewrite this, but I don't want to mess with reproducibility
|
963
|
+
# issues. For now I've just made it a teeny bit more efficient.
|
981
964
|
def random_hermitian(dim):
|
982
965
|
"""
|
983
966
|
Generates a random Hermitian matrix
|
@@ -996,12 +979,13 @@ def random_hermitian(dim):
|
|
996
979
|
dim = int(dim)
|
997
980
|
a = _np.random.random(size=[dim, dim])
|
998
981
|
b = _np.random.random(size=[dim, dim])
|
999
|
-
c = a + 1.j * b
|
982
|
+
c = a + 1.j * b
|
983
|
+
c += c.conj().T
|
1000
984
|
my_norm = norm1(c)
|
1001
985
|
return c / my_norm
|
1002
986
|
|
1003
987
|
|
1004
|
-
def norm1to1(operator, num_samples=10000, mx_basis="gm"
|
988
|
+
def norm1to1(operator, num_samples=10000, mx_basis="gm"):
|
1005
989
|
"""
|
1006
990
|
The Hermitian 1-to-1 norm of a superoperator represented in the standard basis.
|
1007
991
|
|
@@ -1019,23 +1003,20 @@ def norm1to1(operator, num_samples=10000, mx_basis="gm", return_list=False):
|
|
1019
1003
|
mx_basis : {'std', 'gm', 'pp', 'qt'} or Basis
|
1020
1004
|
The basis of `operator`.
|
1021
1005
|
|
1022
|
-
return_list : bool, optional
|
1023
|
-
Whether the entire list of sampled values is returned or just the maximum.
|
1024
|
-
|
1025
1006
|
Returns
|
1026
1007
|
-------
|
1027
1008
|
float or list
|
1028
1009
|
Depends on the value of `return_list`.
|
1029
1010
|
"""
|
1030
1011
|
std_operator = change_basis(operator, mx_basis, 'std')
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1012
|
+
dim = int(_np.sqrt(len(std_operator)))
|
1013
|
+
max_val = 0.0
|
1014
|
+
for _ in range(num_samples):
|
1015
|
+
invec = random_hermitian(dim).ravel(order='F')
|
1016
|
+
outvec = std_operator @ invec
|
1017
|
+
val = norm1(outvec.reshape((dim,dim), order='F'))
|
1018
|
+
max_val = max(val, max_val)
|
1019
|
+
return max_val
|
1039
1020
|
|
1040
1021
|
## ------------------------ General utility fns -----------------------------------
|
1041
1022
|
|
@@ -1345,9 +1326,9 @@ def _fas(a, inds, rhs, add=False):
|
|
1345
1326
|
indx_tups = list(_itertools.product(*b))
|
1346
1327
|
inds = tuple(zip(*indx_tups)) # un-zips to one list per dim
|
1347
1328
|
if add:
|
1348
|
-
a[inds] += rhs.
|
1329
|
+
a[inds] += rhs.ravel()
|
1349
1330
|
else:
|
1350
|
-
a[inds] = rhs.
|
1331
|
+
a[inds] = rhs.ravel()
|
1351
1332
|
|
1352
1333
|
#OLD DEBUG: just a reference for building the C-implementation (this is very slow in python!)
|
1353
1334
|
##Alt: C-able impl
|
@@ -1443,104 +1424,6 @@ def _findx(a, inds, always_copy=False):
|
|
1443
1424
|
return a_inds
|
1444
1425
|
|
1445
1426
|
|
1446
|
-
def safe_dot(a, b):
|
1447
|
-
"""
|
1448
|
-
Performs dot(a,b) correctly when neither, either, or both arguments are sparse matrices.
|
1449
|
-
|
1450
|
-
Parameters
|
1451
|
-
----------
|
1452
|
-
a : numpy.ndarray or scipy.sparse matrix.
|
1453
|
-
First matrix.
|
1454
|
-
|
1455
|
-
b : numpy.ndarray or scipy.sparse matrix.
|
1456
|
-
Second matrix.
|
1457
|
-
|
1458
|
-
Returns
|
1459
|
-
-------
|
1460
|
-
numpy.ndarray or scipy.sparse matrix
|
1461
|
-
"""
|
1462
|
-
if _sps.issparse(a):
|
1463
|
-
return a.dot(b) # sparseMx.dot works for both sparse and dense args
|
1464
|
-
elif _sps.issparse(b):
|
1465
|
-
# to return a sparse mx even when a is dense (asymmetric behavior):
|
1466
|
-
# --> return _sps.csr_matrix(a).dot(b) # numpyMx.dot can't handle sparse argument
|
1467
|
-
return _np.dot(a, b.toarray())
|
1468
|
-
else:
|
1469
|
-
return _np.dot(a, b)
|
1470
|
-
|
1471
|
-
|
1472
|
-
def safe_real(a, inplace=False, check=False):
|
1473
|
-
"""
|
1474
|
-
Get the real-part of `a`, where `a` can be either a dense array or a sparse matrix.
|
1475
|
-
|
1476
|
-
Parameters
|
1477
|
-
----------
|
1478
|
-
a : numpy.ndarray or scipy.sparse matrix.
|
1479
|
-
Array to take real part of.
|
1480
|
-
|
1481
|
-
inplace : bool, optional
|
1482
|
-
Whether this operation should be done in-place.
|
1483
|
-
|
1484
|
-
check : bool, optional
|
1485
|
-
If True, raise a `ValueError` if `a` has a nonzero imaginary part.
|
1486
|
-
|
1487
|
-
Returns
|
1488
|
-
-------
|
1489
|
-
numpy.ndarray or scipy.sparse matrix
|
1490
|
-
"""
|
1491
|
-
if check:
|
1492
|
-
assert(safe_norm(a, 'imag') < 1e-6), "Check failed: taking real-part of matrix w/nonzero imaginary part"
|
1493
|
-
if _sps.issparse(a):
|
1494
|
-
if _sps.isspmatrix_csr(a):
|
1495
|
-
if inplace:
|
1496
|
-
ret = _sps.csr_matrix((_np.real(a.data), a.indices, a.indptr), shape=a.shape, dtype='d')
|
1497
|
-
else: # copy
|
1498
|
-
ret = _sps.csr_matrix((_np.real(a.data).copy(), a.indices.copy(),
|
1499
|
-
a.indptr.copy()), shape=a.shape, dtype='d')
|
1500
|
-
ret.eliminate_zeros()
|
1501
|
-
return ret
|
1502
|
-
else:
|
1503
|
-
raise NotImplementedError("safe_real() doesn't work with %s matrices yet" % str(type(a)))
|
1504
|
-
else:
|
1505
|
-
return _np.real(a)
|
1506
|
-
|
1507
|
-
|
1508
|
-
def safe_imag(a, inplace=False, check=False):
|
1509
|
-
"""
|
1510
|
-
Get the imaginary-part of `a`, where `a` can be either a dense array or a sparse matrix.
|
1511
|
-
|
1512
|
-
Parameters
|
1513
|
-
----------
|
1514
|
-
a : numpy.ndarray or scipy.sparse matrix.
|
1515
|
-
Array to take imaginary part of.
|
1516
|
-
|
1517
|
-
inplace : bool, optional
|
1518
|
-
Whether this operation should be done in-place.
|
1519
|
-
|
1520
|
-
check : bool, optional
|
1521
|
-
If True, raise a `ValueError` if `a` has a nonzero real part.
|
1522
|
-
|
1523
|
-
Returns
|
1524
|
-
-------
|
1525
|
-
numpy.ndarray or scipy.sparse matrix
|
1526
|
-
"""
|
1527
|
-
if check:
|
1528
|
-
assert(safe_norm(a, 'real') < 1e-6), "Check failed: taking imag-part of matrix w/nonzero real part"
|
1529
|
-
if _sps.issparse(a):
|
1530
|
-
if _sps.isspmatrix_csr(a):
|
1531
|
-
if inplace:
|
1532
|
-
ret = _sps.csr_matrix((_np.imag(a.data), a.indices, a.indptr), shape=a.shape, dtype='d')
|
1533
|
-
else: # copy
|
1534
|
-
ret = _sps.csr_matrix((_np.imag(a.data).copy(), a.indices.copy(),
|
1535
|
-
a.indptr.copy()), shape=a.shape, dtype='d')
|
1536
|
-
ret.eliminate_zeros()
|
1537
|
-
return ret
|
1538
|
-
else:
|
1539
|
-
raise NotImplementedError("safe_real() doesn't work with %s matrices yet" % str(type(a)))
|
1540
|
-
else:
|
1541
|
-
return _np.imag(a)
|
1542
|
-
|
1543
|
-
|
1544
1427
|
def safe_norm(a, part=None):
|
1545
1428
|
"""
|
1546
1429
|
Get the frobenius norm of a matrix or vector, `a`, when it is either a dense array or a sparse matrix.
|
@@ -1950,23 +1833,6 @@ def _custom_expm_multiply_simple_core(a, b, mu, m_star, s, tol, eta): # t == 1.
|
|
1950
1833
|
return F
|
1951
1834
|
|
1952
1835
|
|
1953
|
-
#From SciPy source, as a reference - above we assume A is a sparse csr matrix
|
1954
|
-
# and B is a dense vector
|
1955
|
-
#def _exact_inf_norm(A):
|
1956
|
-
# # A compatibility function which should eventually disappear.
|
1957
|
-
# if scipy.sparse.isspmatrix(A):
|
1958
|
-
# return max(abs(A).sum(axis=1).flat)
|
1959
|
-
# else:
|
1960
|
-
# return np.linalg.norm(A, np.inf)
|
1961
|
-
#
|
1962
|
-
#
|
1963
|
-
#def _exact_1_norm(A):
|
1964
|
-
# # A compatibility function which should eventually disappear.
|
1965
|
-
# if scipy.sparse.isspmatrix(A):
|
1966
|
-
# return max(abs(A).sum(axis=0).flat)
|
1967
|
-
# else:
|
1968
|
-
# return np.linalg.norm(A, 1)
|
1969
|
-
|
1970
1836
|
def expop_multiply_prep(op, a_1_norm=None, tol=EXPM_DEFAULT_TOL):
|
1971
1837
|
"""
|
1972
1838
|
Returns "prepared" meta-info about operation op, which is assumed to be traceless (so no shift is needed).
|
@@ -2115,7 +1981,7 @@ def to_unitary(scaled_unitary):
|
|
2115
1981
|
unitary : ndarray
|
2116
1982
|
Such that `scale * unitary == scaled_unitary`.
|
2117
1983
|
"""
|
2118
|
-
scaled_identity =
|
1984
|
+
scaled_identity = gram_matrix(scaled_unitary, adjoint=True)
|
2119
1985
|
scale = _np.sqrt(scaled_identity[0, 0])
|
2120
1986
|
assert(_np.allclose(scaled_identity / (scale**2), _np.identity(scaled_identity.shape[0], 'd'))), \
|
2121
1987
|
"Given `scaled_unitary` does not appear to be a scaled unitary matrix!"
|
@@ -2314,30 +2180,6 @@ def project_onto_antikite(mx, kite):
|
|
2314
2180
|
return mx
|
2315
2181
|
|
2316
2182
|
|
2317
|
-
def remove_dependent_cols(mx, tol=1e-7):
|
2318
|
-
"""
|
2319
|
-
Removes the linearly dependent columns of a matrix.
|
2320
|
-
|
2321
|
-
Parameters
|
2322
|
-
----------
|
2323
|
-
mx : numpy.ndarray
|
2324
|
-
The input matrix
|
2325
|
-
|
2326
|
-
Returns
|
2327
|
-
-------
|
2328
|
-
A linearly independent subset of the columns of `mx`.
|
2329
|
-
"""
|
2330
|
-
last_rank = 0; cols_to_remove = []
|
2331
|
-
for j in range(mx.shape[1]):
|
2332
|
-
rnk = _np.linalg.matrix_rank(mx[:, 0:j + 1], tol)
|
2333
|
-
if rnk == last_rank:
|
2334
|
-
cols_to_remove.append(j)
|
2335
|
-
else:
|
2336
|
-
last_rank = rnk
|
2337
|
-
#print("Removing %d cols" % len(cols_to_remove))
|
2338
|
-
return _np.delete(mx, cols_to_remove, axis=1)
|
2339
|
-
|
2340
|
-
|
2341
2183
|
def intersection_space(space1, space2, tol=1e-7, use_nice_nullspace=False):
|
2342
2184
|
"""
|
2343
2185
|
TODO: docstring
|
@@ -2353,16 +2195,8 @@ def union_space(space1, space2, tol=1e-7):
|
|
2353
2195
|
TODO: docstring
|
2354
2196
|
"""
|
2355
2197
|
VW = _np.concatenate((space1, space2), axis=1)
|
2356
|
-
|
2357
|
-
|
2358
|
-
|
2359
|
-
#UNUSED
|
2360
|
-
#def spectral_radius(x):
|
2361
|
-
# if hasattr(x, 'ndim') and x.ndim == 2: # then interpret as a numpy array and take norm
|
2362
|
-
# evals = _np.sort(_np.linalg.eigvals(x))
|
2363
|
-
# return abs(evals[-1] - evals[0])
|
2364
|
-
# else:
|
2365
|
-
# return x
|
2198
|
+
indep_cols = independent_columns(VW, None, tol)
|
2199
|
+
return VW[:, indep_cols]
|
2366
2200
|
|
2367
2201
|
|
2368
2202
|
def jamiolkowski_angle(hamiltonian_mx):
|