Trajectree 0.0.1__py3-none-any.whl → 0.0.3__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.
Files changed (124) hide show
  1. trajectree/__init__.py +0 -3
  2. trajectree/fock_optics/devices.py +1 -1
  3. trajectree/fock_optics/light_sources.py +2 -2
  4. trajectree/fock_optics/measurement.py +9 -9
  5. trajectree/fock_optics/outputs.py +10 -6
  6. trajectree/fock_optics/utils.py +9 -6
  7. trajectree/sequence/swap.py +5 -4
  8. trajectree/trajectory.py +5 -4
  9. {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/METADATA +2 -3
  10. trajectree-0.0.3.dist-info/RECORD +16 -0
  11. trajectree/quimb/docs/_pygments/_pygments_dark.py +0 -118
  12. trajectree/quimb/docs/_pygments/_pygments_light.py +0 -118
  13. trajectree/quimb/docs/conf.py +0 -158
  14. trajectree/quimb/docs/examples/ex_mpi_expm_evo.py +0 -62
  15. trajectree/quimb/quimb/__init__.py +0 -507
  16. trajectree/quimb/quimb/calc.py +0 -1491
  17. trajectree/quimb/quimb/core.py +0 -2279
  18. trajectree/quimb/quimb/evo.py +0 -712
  19. trajectree/quimb/quimb/experimental/__init__.py +0 -0
  20. trajectree/quimb/quimb/experimental/autojittn.py +0 -129
  21. trajectree/quimb/quimb/experimental/belief_propagation/__init__.py +0 -109
  22. trajectree/quimb/quimb/experimental/belief_propagation/bp_common.py +0 -397
  23. trajectree/quimb/quimb/experimental/belief_propagation/d1bp.py +0 -316
  24. trajectree/quimb/quimb/experimental/belief_propagation/d2bp.py +0 -653
  25. trajectree/quimb/quimb/experimental/belief_propagation/hd1bp.py +0 -571
  26. trajectree/quimb/quimb/experimental/belief_propagation/hv1bp.py +0 -775
  27. trajectree/quimb/quimb/experimental/belief_propagation/l1bp.py +0 -316
  28. trajectree/quimb/quimb/experimental/belief_propagation/l2bp.py +0 -537
  29. trajectree/quimb/quimb/experimental/belief_propagation/regions.py +0 -194
  30. trajectree/quimb/quimb/experimental/cluster_update.py +0 -286
  31. trajectree/quimb/quimb/experimental/merabuilder.py +0 -865
  32. trajectree/quimb/quimb/experimental/operatorbuilder/__init__.py +0 -15
  33. trajectree/quimb/quimb/experimental/operatorbuilder/operatorbuilder.py +0 -1631
  34. trajectree/quimb/quimb/experimental/schematic.py +0 -7
  35. trajectree/quimb/quimb/experimental/tn_marginals.py +0 -130
  36. trajectree/quimb/quimb/experimental/tnvmc.py +0 -1483
  37. trajectree/quimb/quimb/gates.py +0 -36
  38. trajectree/quimb/quimb/gen/__init__.py +0 -2
  39. trajectree/quimb/quimb/gen/operators.py +0 -1167
  40. trajectree/quimb/quimb/gen/rand.py +0 -713
  41. trajectree/quimb/quimb/gen/states.py +0 -479
  42. trajectree/quimb/quimb/linalg/__init__.py +0 -6
  43. trajectree/quimb/quimb/linalg/approx_spectral.py +0 -1109
  44. trajectree/quimb/quimb/linalg/autoblock.py +0 -258
  45. trajectree/quimb/quimb/linalg/base_linalg.py +0 -719
  46. trajectree/quimb/quimb/linalg/mpi_launcher.py +0 -397
  47. trajectree/quimb/quimb/linalg/numpy_linalg.py +0 -244
  48. trajectree/quimb/quimb/linalg/rand_linalg.py +0 -514
  49. trajectree/quimb/quimb/linalg/scipy_linalg.py +0 -293
  50. trajectree/quimb/quimb/linalg/slepc_linalg.py +0 -892
  51. trajectree/quimb/quimb/schematic.py +0 -1518
  52. trajectree/quimb/quimb/tensor/__init__.py +0 -401
  53. trajectree/quimb/quimb/tensor/array_ops.py +0 -610
  54. trajectree/quimb/quimb/tensor/circuit.py +0 -4824
  55. trajectree/quimb/quimb/tensor/circuit_gen.py +0 -411
  56. trajectree/quimb/quimb/tensor/contraction.py +0 -336
  57. trajectree/quimb/quimb/tensor/decomp.py +0 -1255
  58. trajectree/quimb/quimb/tensor/drawing.py +0 -1646
  59. trajectree/quimb/quimb/tensor/fitting.py +0 -385
  60. trajectree/quimb/quimb/tensor/geometry.py +0 -583
  61. trajectree/quimb/quimb/tensor/interface.py +0 -114
  62. trajectree/quimb/quimb/tensor/networking.py +0 -1058
  63. trajectree/quimb/quimb/tensor/optimize.py +0 -1818
  64. trajectree/quimb/quimb/tensor/tensor_1d.py +0 -4778
  65. trajectree/quimb/quimb/tensor/tensor_1d_compress.py +0 -1854
  66. trajectree/quimb/quimb/tensor/tensor_1d_tebd.py +0 -662
  67. trajectree/quimb/quimb/tensor/tensor_2d.py +0 -5954
  68. trajectree/quimb/quimb/tensor/tensor_2d_compress.py +0 -96
  69. trajectree/quimb/quimb/tensor/tensor_2d_tebd.py +0 -1230
  70. trajectree/quimb/quimb/tensor/tensor_3d.py +0 -2869
  71. trajectree/quimb/quimb/tensor/tensor_3d_tebd.py +0 -46
  72. trajectree/quimb/quimb/tensor/tensor_approx_spectral.py +0 -60
  73. trajectree/quimb/quimb/tensor/tensor_arbgeom.py +0 -3237
  74. trajectree/quimb/quimb/tensor/tensor_arbgeom_compress.py +0 -565
  75. trajectree/quimb/quimb/tensor/tensor_arbgeom_tebd.py +0 -1138
  76. trajectree/quimb/quimb/tensor/tensor_builder.py +0 -5411
  77. trajectree/quimb/quimb/tensor/tensor_core.py +0 -11179
  78. trajectree/quimb/quimb/tensor/tensor_dmrg.py +0 -1472
  79. trajectree/quimb/quimb/tensor/tensor_mera.py +0 -204
  80. trajectree/quimb/quimb/utils.py +0 -892
  81. trajectree/quimb/tests/__init__.py +0 -0
  82. trajectree/quimb/tests/test_accel.py +0 -501
  83. trajectree/quimb/tests/test_calc.py +0 -788
  84. trajectree/quimb/tests/test_core.py +0 -847
  85. trajectree/quimb/tests/test_evo.py +0 -565
  86. trajectree/quimb/tests/test_gen/__init__.py +0 -0
  87. trajectree/quimb/tests/test_gen/test_operators.py +0 -361
  88. trajectree/quimb/tests/test_gen/test_rand.py +0 -296
  89. trajectree/quimb/tests/test_gen/test_states.py +0 -261
  90. trajectree/quimb/tests/test_linalg/__init__.py +0 -0
  91. trajectree/quimb/tests/test_linalg/test_approx_spectral.py +0 -368
  92. trajectree/quimb/tests/test_linalg/test_base_linalg.py +0 -351
  93. trajectree/quimb/tests/test_linalg/test_mpi_linalg.py +0 -127
  94. trajectree/quimb/tests/test_linalg/test_numpy_linalg.py +0 -84
  95. trajectree/quimb/tests/test_linalg/test_rand_linalg.py +0 -134
  96. trajectree/quimb/tests/test_linalg/test_slepc_linalg.py +0 -283
  97. trajectree/quimb/tests/test_tensor/__init__.py +0 -0
  98. trajectree/quimb/tests/test_tensor/test_belief_propagation/__init__.py +0 -0
  99. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d1bp.py +0 -39
  100. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_d2bp.py +0 -67
  101. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hd1bp.py +0 -64
  102. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_hv1bp.py +0 -51
  103. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l1bp.py +0 -142
  104. trajectree/quimb/tests/test_tensor/test_belief_propagation/test_l2bp.py +0 -101
  105. trajectree/quimb/tests/test_tensor/test_circuit.py +0 -816
  106. trajectree/quimb/tests/test_tensor/test_contract.py +0 -67
  107. trajectree/quimb/tests/test_tensor/test_decomp.py +0 -40
  108. trajectree/quimb/tests/test_tensor/test_mera.py +0 -52
  109. trajectree/quimb/tests/test_tensor/test_optimizers.py +0 -488
  110. trajectree/quimb/tests/test_tensor/test_tensor_1d.py +0 -1171
  111. trajectree/quimb/tests/test_tensor/test_tensor_2d.py +0 -606
  112. trajectree/quimb/tests/test_tensor/test_tensor_2d_tebd.py +0 -144
  113. trajectree/quimb/tests/test_tensor/test_tensor_3d.py +0 -123
  114. trajectree/quimb/tests/test_tensor/test_tensor_arbgeom.py +0 -226
  115. trajectree/quimb/tests/test_tensor/test_tensor_builder.py +0 -441
  116. trajectree/quimb/tests/test_tensor/test_tensor_core.py +0 -2066
  117. trajectree/quimb/tests/test_tensor/test_tensor_dmrg.py +0 -388
  118. trajectree/quimb/tests/test_tensor/test_tensor_spectral_approx.py +0 -63
  119. trajectree/quimb/tests/test_tensor/test_tensor_tebd.py +0 -270
  120. trajectree/quimb/tests/test_utils.py +0 -85
  121. trajectree-0.0.1.dist-info/RECORD +0 -126
  122. {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/WHEEL +0 -0
  123. {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/licenses/LICENSE +0 -0
  124. {trajectree-0.0.1.dist-info → trajectree-0.0.3.dist-info}/top_level.txt +0 -0
@@ -1,713 +0,0 @@
1
- """Functions for generating random quantum objects and states."""
2
-
3
- import math
4
- import random
5
- from functools import wraps
6
- from numbers import Integral
7
- from itertools import count, chain
8
- from concurrent.futures import wait
9
-
10
- import numpy as np
11
- import numpy.random
12
- import scipy.sparse as sp
13
-
14
- from ..core import (
15
- _NUM_THREAD_WORKERS,
16
- complex_array,
17
- dag,
18
- dot,
19
- get_thread_pool,
20
- kron,
21
- nmlz,
22
- prod,
23
- ptr,
24
- pvectorize,
25
- qarray,
26
- qu,
27
- rdmul,
28
- vectorize,
29
- )
30
-
31
-
32
- class _RGenHandler:
33
- """Private object that handles pool of random number generators for
34
- parallel number generation - seeding them & changing the underlying bit
35
- generators.
36
- """
37
-
38
- def __init__(self, initial_seed=None, initial_bitgen=None):
39
- self.rgs = []
40
- self.set_seed(initial_seed)
41
- self.set_bitgen(initial_bitgen)
42
-
43
- def set_bitgen(self, bitgen):
44
- """Set the core underlying bit-generator.
45
-
46
- Parameters
47
- ----------
48
- bitgen : {None, str}
49
- Which bit generator to use, either from numpy or `randomgen` -
50
- https://bashtage.github.io/randomgen/bit_generators/index.html.
51
- """
52
-
53
- if bitgen is None:
54
- self.gen_fn = numpy.random.default_rng
55
-
56
- else:
57
- try:
58
- # try numpy first
59
- bg = getattr(numpy.random, bitgen)
60
- except AttributeError:
61
- # and then (now largely deprecated) randomgen
62
- import randomgen
63
-
64
- bg = getattr(randomgen, bitgen)
65
-
66
- def gen(s):
67
- return numpy.random.Generator(bg(s))
68
-
69
- self.gen_fn = gen
70
-
71
- # delete any old rgens
72
- self.rgs = []
73
-
74
- def set_seed(self, seed=None):
75
- """Set the seed for the bit generators.
76
-
77
- Parameters
78
- ----------
79
- seed : {None, int}, optional
80
- Seed supplied to `numpy.random.SeedSequence`. None will randomly
81
- the generators (default).
82
- """
83
- seq = numpy.random.SeedSequence(seed)
84
-
85
- # compute seeds in batches of 4 for perf
86
- self.seeds = iter(chain.from_iterable(seq.spawn(4) for _ in count()))
87
-
88
- # delete any old rgens
89
- self.rgs = []
90
-
91
- def get_rgens(self, num_threads):
92
- """Get a list of the :class:`numpy.random.Generator` instances, having
93
- made sure there are at least ``num_threads``.
94
-
95
- Parameters
96
- ----------
97
- num_threads : int
98
- The number of generators to return.
99
-
100
- Returns
101
- -------
102
- list[numpy.random.Generator]
103
- """
104
- num_gens = len(self.rgs)
105
-
106
- if num_gens < num_threads:
107
- self.rgs.extend(
108
- self.gen_fn(next(self.seeds))
109
- for _ in range(num_gens, num_threads)
110
- )
111
-
112
- return self.rgs[:num_threads]
113
-
114
-
115
- _RG_HANDLER = _RGenHandler()
116
-
117
-
118
- def seed_rand(seed):
119
- """See the random number generators, by instantiating a new set of bit
120
- generators with a 'seed sequence'.
121
- """
122
- global _RG_HANDLER
123
- return _RG_HANDLER.set_seed(seed)
124
-
125
-
126
- def set_rand_bitgen(bitgen):
127
- """Set the core bit generator type to use, from either ``numpy`` or
128
- ``randomgen``.
129
-
130
- Parameters
131
- ----------
132
- bitgen : {'PCG64', 'SFC64', 'MT19937', 'Philox', str}
133
- Which bit generator to use.
134
- """
135
- global _RG_HANDLER
136
- return _RG_HANDLER.set_bitgen(bitgen)
137
-
138
-
139
- def _get_rgens(num_threads):
140
- global _RG_HANDLER
141
- return _RG_HANDLER.get_rgens(num_threads)
142
-
143
-
144
- def randn(
145
- shape=(),
146
- dtype=float,
147
- scale=1.0,
148
- loc=0.0,
149
- num_threads=None,
150
- seed=None,
151
- dist="normal",
152
- ):
153
- """Fast multithreaded generation of random normally distributed data.
154
-
155
- Parameters
156
- ----------
157
- shape : tuple[int]
158
- The shape of the output random array.
159
- dtype : {'complex128', 'float64', 'complex64' 'float32'}, optional
160
- The data-type of the output array.
161
- scale : float, optional
162
- A multiplicative scale for the random numbers.
163
- loc : float, optional
164
- An additive location for the random numbers.
165
- num_threads : int, optional
166
- How many threads to use. If ``None``, decide automatically.
167
- dist : {'normal', 'uniform', 'rademacher', 'exp'}, optional
168
- Type of random number to generate.
169
- """
170
- if seed is not None:
171
- seed_rand(seed)
172
-
173
- if isinstance(shape, Integral):
174
- d = shape
175
- shape = (shape,)
176
- else:
177
- d = prod(shape)
178
-
179
- if dist == "rademacher":
180
- # not parallelized for now
181
- return rand_rademacher(shape, scale=scale, loc=loc, dtype=dtype)
182
-
183
- if num_threads is None:
184
- # only multi-thread for big ``d``
185
- if d <= 32768:
186
- num_threads = 1
187
- else:
188
- num_threads = _NUM_THREAD_WORKERS
189
-
190
- rgs = _get_rgens(num_threads)
191
-
192
- gen_method = {
193
- "uniform": "random",
194
- "normal": "standard_normal",
195
- "exp": "standard_exponential",
196
- }.get(dist, dist)
197
-
198
- # sequential generation
199
- if num_threads <= 1:
200
-
201
- def create(d, dtype):
202
- out = np.empty(d, dtype)
203
- getattr(rgs[0], gen_method)(out=out, dtype=dtype)
204
- return out
205
-
206
- # threaded generation
207
- else:
208
- pool = get_thread_pool()
209
- S = math.ceil(d / num_threads)
210
-
211
- def _fill(gen, out, dtype, first, last):
212
- getattr(gen, gen_method)(out=out[first:last], dtype=dtype)
213
-
214
- def create(d, dtype):
215
- out = np.empty(d, dtype)
216
- # submit thread work
217
- fs = [
218
- pool.submit(_fill, gen, out, dtype, i * S, (i + 1) * S)
219
- for i, gen in enumerate(rgs)
220
- ]
221
- wait(fs)
222
- return out
223
-
224
- if np.issubdtype(dtype, np.floating):
225
- out = create(d, dtype)
226
-
227
- elif np.issubdtype(dtype, np.complexfloating):
228
- # need to sum two real arrays if generating complex numbers
229
- if np.issubdtype(dtype, np.complex64):
230
- sub_dtype = np.float32
231
- else:
232
- sub_dtype = np.float64
233
-
234
- out = complex_array(create(d, sub_dtype), create(d, sub_dtype))
235
-
236
- else:
237
- raise ValueError(f"dtype {dtype} not understood.")
238
-
239
- if out.dtype != dtype:
240
- out = out.astype(dtype)
241
-
242
- if scale != 1.0:
243
- out *= scale
244
- if loc != 0.0:
245
- out += loc
246
-
247
- return out.reshape(shape)
248
-
249
-
250
- @wraps(randn)
251
- def rand(*args, **kwargs):
252
- kwargs.setdefault("dist", "uniform")
253
- return randn(*args, **kwargs)
254
-
255
-
256
- def random_seed_fn(fn):
257
- """Modify ``fn`` to take a ``seed`` argument (so as to seed the random
258
- generators once-only at beginning of function not every ``randn`` call).
259
- """
260
-
261
- @wraps(fn)
262
- def wrapped_fn(*args, seed=None, **kwargs):
263
- if seed is not None:
264
- seed_rand(seed)
265
- return fn(*args, **kwargs)
266
-
267
- return wrapped_fn
268
-
269
-
270
- def _randint(*args, **kwargs):
271
- return _get_rgens(1)[0].integers(*args, **kwargs)
272
-
273
-
274
- def _choice(*args, **kwargs):
275
- return _get_rgens(1)[0].choice(*args, **kwargs)
276
-
277
-
278
- choice = random_seed_fn(_choice)
279
-
280
-
281
- @random_seed_fn
282
- def rand_rademacher(shape, scale=1, loc=0.0, dtype=float):
283
- """ """
284
- if np.issubdtype(dtype, np.floating):
285
- entries = loc + np.array([1.0, -1.0]) * scale
286
- need2convert = dtype not in (float, np.float64)
287
-
288
- elif np.issubdtype(dtype, np.complexfloating):
289
- entries = loc + np.array([1.0, -1.0, 1.0j, -1.0j]) * scale
290
- need2convert = dtype not in (complex, np.complex128)
291
-
292
- else:
293
- raise TypeError(
294
- f"dtype {dtype} not understood - should be float or complex."
295
- )
296
-
297
- x = _choice(entries, shape)
298
- if need2convert:
299
- x = x.astype(dtype)
300
-
301
- return x
302
-
303
-
304
- def _phase_to_complex_base(x):
305
- return 1j * math.sin(x) + math.cos(x)
306
-
307
-
308
- _phase_sigs = ["complex64(float32)", "complex128(float64)"]
309
- _phase_to_complex_seq = vectorize(_phase_sigs)(_phase_to_complex_base)
310
- """Turn array of phases into unit circle complex numbers - sequential.
311
- """
312
- _phase_to_complex_par = pvectorize(_phase_sigs)(_phase_to_complex_base)
313
- """Turn array of phases into unit circle complex numbers - parallel.
314
- """
315
-
316
-
317
- def phase_to_complex(x):
318
- if x.size >= 512:
319
- return _phase_to_complex_par(x)
320
- # XXX: this is not as fast as numexpr - investigate?
321
- return _phase_to_complex_seq(x)
322
-
323
-
324
- @random_seed_fn
325
- def rand_phase(shape, scale=1, dtype=complex):
326
- """Generate random complex numbers distributed on the unit sphere."""
327
- if not np.issubdtype(dtype, np.complexfloating):
328
- raise ValueError(f"dtype must be complex, got '{dtype}'.")
329
-
330
- if np.issubdtype(dtype, np.complex64):
331
- sub_dtype = np.float32
332
- else:
333
- sub_dtype = np.float64
334
-
335
- phi = randn(shape, dtype=sub_dtype, scale=2 * math.pi, dist="uniform")
336
- z = phase_to_complex(phi)
337
- if scale != 1:
338
- z *= scale
339
-
340
- return z
341
-
342
-
343
- def get_rand_fill_fn(
344
- dist="normal",
345
- loc=0.0,
346
- scale=1.0,
347
- seed=None,
348
- dtype="float64",
349
- ):
350
- """Get a callable with the given random distribution and parameters, that
351
- has signature ``fill_fn(shape) -> array``.
352
-
353
- Parameters
354
- ----------
355
- dist : {'normal', 'uniform', 'rademacher', 'exp'}, optional
356
- Type of random number to generate, defaults to 'normal'.
357
- loc : float, optional
358
- An additive offset to add to the random numbers.
359
- scale : float, optional
360
- A multiplicative factor to scale the random numbers by.
361
- seed : int, optional
362
- A random seed.
363
- dtype : {'float64', 'complex128', 'float32', 'complex64'}, optional
364
- The underlying data type.
365
-
366
- Returns
367
- -------
368
- callable
369
- """
370
- if seed is not None:
371
- seed_rand(seed)
372
-
373
- def fill_fn(shape=()):
374
- return randn(shape, dtype=dtype, dist=dist, loc=loc, scale=scale)
375
-
376
- return fill_fn
377
-
378
-
379
- def rand_matrix(
380
- d,
381
- scaled=True,
382
- sparse=False,
383
- stype="csr",
384
- density=None,
385
- dtype=complex,
386
- seed=None,
387
- ):
388
- """Generate a random matrix of order `d` with normally distributed
389
- entries. If `scaled` is `True`, then in the limit of large `d` the
390
- eigenvalues will be distributed on the unit complex disk.
391
-
392
- Parameters
393
- ----------
394
- d : int
395
- Matrix dimension.
396
- scaled : bool, optional
397
- Whether to scale the matrices values such that its spectrum
398
- approximately lies on the unit disk (for dense matrices).
399
- sparse : bool, optional
400
- Whether to produce a sparse matrix.
401
- stype : {'csr', 'csc', 'coo', ...}, optional
402
- The type of sparse matrix if ``sparse=True``.
403
- density : float, optional
404
- Target density of non-zero elements for the sparse matrix. By default
405
- aims for about 10 entries per row.
406
- dtype : {complex, float}, optional
407
- The data type of the matrix elements.
408
-
409
- Returns
410
- -------
411
- mat : qarray or sparse matrix
412
- Random matrix.
413
- """
414
- if np.issubdtype(dtype, np.floating):
415
- iscomplex = False
416
- elif np.issubdtype(dtype, np.complexfloating):
417
- iscomplex = True
418
- else:
419
- raise TypeError(
420
- f"dtype {dtype} not understood - should be " "float or complex."
421
- )
422
-
423
- # handle seed manually since standard python random.seed might be called
424
- if seed is not None:
425
- seed_rand(seed)
426
-
427
- if sparse:
428
- # Aim for 10 non-zero values per row, but betwen 1 and d/2
429
- density = min(10, d / 2) / d if density is None else density
430
- density = min(
431
- max(
432
- d**-2,
433
- density,
434
- ),
435
- 1.0,
436
- )
437
- nnz = round(density * d * d)
438
-
439
- if density > 0.1:
440
- # take special care to avoid duplicates
441
- if seed is not None:
442
- random.seed(seed)
443
- ijs = random.sample(range(0, d**2), k=nnz)
444
- else:
445
- ijs = _randint(0, d * d, size=nnz)
446
-
447
- # want to sample nnz unique (d, d) pairs without building list
448
- i, j = np.divmod(ijs, d)
449
-
450
- data = randn(nnz, dtype=dtype)
451
- mat = sp.coo_matrix((data, (i, j)), shape=(d, d)).asformat(stype)
452
- else:
453
- density = 1.0
454
- mat = qarray(randn((d, d), dtype=dtype))
455
-
456
- if scaled:
457
- mat /= ((2 if iscomplex else 1) * d * density) ** 0.5
458
-
459
- return mat
460
-
461
-
462
- @random_seed_fn
463
- def rand_herm(d, sparse=False, density=None, dtype=complex):
464
- """Generate a random hermitian operator of order `d` with normally
465
- distributed entries. In the limit of large `d` the spectrum will be a
466
- semi-circular distribution between [-1, 1].
467
-
468
- See Also
469
- --------
470
- rand_matrix, rand_pos, rand_rho, rand_uni
471
- """
472
- if sparse:
473
- density = 10 / d if density is None else density
474
- density = min(max(density, d**-2), 1 - d**-2)
475
- density /= 2 # to account of herm construction
476
-
477
- herm = rand_matrix(
478
- d, scaled=True, sparse=sparse, density=density, dtype=dtype
479
- )
480
-
481
- if sparse:
482
- herm.data /= 2**1.5
483
- else:
484
- herm /= 2**1.5
485
-
486
- herm += dag(herm)
487
-
488
- return herm
489
-
490
-
491
- @random_seed_fn
492
- def rand_pos(d, sparse=False, density=None, dtype=complex):
493
- """Generate a random positive operator of size `d`, with normally
494
- distributed entries. In the limit of large `d` the spectrum will lie
495
- between [0, 1].
496
-
497
- See Also
498
- --------
499
- rand_matrix, rand_herm, rand_rho, rand_uni
500
- """
501
- if sparse:
502
- density = 10 / d if density is None else density
503
- density = min(max(density, d**-2), 1 - d**-2)
504
- density = 0.5 * (density / d) ** 0.5 # to account for pos construction
505
-
506
- pos = rand_matrix(
507
- d, scaled=True, sparse=sparse, density=density, dtype=dtype
508
- )
509
-
510
- return dot(pos, dag(pos))
511
-
512
-
513
- @random_seed_fn
514
- def rand_rho(d, sparse=False, density=None, dtype=complex):
515
- """Generate a random positive operator of size `d` with normally
516
- distributed entries and unit trace.
517
-
518
- See Also
519
- --------
520
- rand_matrix, rand_herm, rand_pos, rand_uni
521
- """
522
- return nmlz(rand_pos(d, sparse=sparse, density=density, dtype=dtype))
523
-
524
-
525
- @random_seed_fn
526
- def rand_uni(d, dtype=complex):
527
- """Generate a random unitary operator of size `d`, distributed according to
528
- the Haar measure.
529
-
530
- See Also
531
- --------
532
- rand_matrix, rand_herm, rand_pos, rand_rho
533
- """
534
- q, r = np.linalg.qr(rand_matrix(d, dtype=dtype))
535
- r = np.diagonal(r)
536
- r = r / np.abs(r) # read-only so not inplace
537
- return rdmul(q, r)
538
-
539
-
540
- @random_seed_fn
541
- def rand_ket(d, sparse=False, stype="csr", density=0.01, dtype=complex):
542
- """Generates a ket of length `d` with normally distributed entries."""
543
- if sparse:
544
- ket = sp.random(d, 1, format=stype, density=density)
545
- ket.data = randn((ket.nnz,), dtype=dtype)
546
- else:
547
- ket = qarray(randn((d, 1), dtype=dtype))
548
- return nmlz(ket)
549
-
550
-
551
- @random_seed_fn
552
- def rand_haar_state(d, dtype=complex):
553
- """Generate a random state of dimension `d` according to the Haar
554
- distribution.
555
- """
556
- u = rand_uni(d, dtype=dtype)
557
- return u[:, [0]]
558
-
559
-
560
- @random_seed_fn
561
- def gen_rand_haar_states(d, reps, dtype=complex):
562
- """Generate many random Haar states, recycling a random unitary operator
563
- by using all of its columns (not a good idea?).
564
- """
565
- for rep in range(reps):
566
- cyc = rep % d
567
- if cyc == 0:
568
- u = rand_uni(d, dtype=dtype)
569
- yield u[:, [cyc]]
570
-
571
-
572
- @random_seed_fn
573
- def rand_mix(d, tr_d_min=None, tr_d_max=None, mode="rand", dtype=complex):
574
- """Constructs a random mixed state by tracing out a random ket
575
- where the composite system varies in size between 2 and d. This produces
576
- a spread of states including more purity but has no real meaning.
577
- """
578
- if tr_d_min is None:
579
- tr_d_min = 2
580
- if tr_d_max is None:
581
- tr_d_max = d
582
-
583
- m = _randint(tr_d_min, tr_d_max)
584
- if mode == "rand":
585
- psi = rand_ket(d * m, dtype=dtype)
586
- elif mode == "haar":
587
- psi = rand_haar_state(d * m, dtype=dtype)
588
-
589
- return ptr(psi, [d, m], 0)
590
-
591
-
592
- @random_seed_fn
593
- def rand_product_state(n, qtype=None, dtype=complex):
594
- """Generates a ket of `n` many random pure qubits."""
595
-
596
- def gen_rand_pure_qubits(n):
597
- for _ in range(n):
598
- (u,) = rand(1)
599
- (v,) = rand(1)
600
- phi = 2 * np.pi * u
601
- theta = np.arccos(2 * v - 1)
602
- yield qu(
603
- [
604
- [np.cos(theta / 2.0)],
605
- [np.sin(theta / 2.0) * np.exp(1.0j * phi)],
606
- ],
607
- qtype=qtype,
608
- dtype=dtype,
609
- )
610
-
611
- return kron(*gen_rand_pure_qubits(n))
612
-
613
-
614
- @random_seed_fn
615
- def rand_matrix_product_state(
616
- n, bond_dim, phys_dim=2, dtype=complex, cyclic=False, trans_invar=False
617
- ):
618
- """Generate a random matrix product state (in dense form, see
619
- :func:`~quimb.tensor.MPS_rand_state` for tensor network form).
620
-
621
- Parameters
622
- ----------
623
- n : int
624
- Number of sites.
625
- bond_dim : int
626
- Dimension of the bond (virtual) indices.
627
- phys_dim : int, optional
628
- Physical dimension of each local site, defaults to 2 (qubits).
629
- cyclic : bool (optional)
630
- Whether to impose cyclic boundary conditions on the entanglement
631
- structure.
632
- trans_invar : bool (optional)
633
- Whether to generate a translationally invariant state,
634
- requires cyclic=True.
635
-
636
- Returns
637
- -------
638
- ket : qarray
639
- The random state, with shape (phys_dim**n, 1)
640
-
641
- """
642
- from quimb.tensor import MPS_rand_state
643
-
644
- mps = MPS_rand_state(
645
- n,
646
- bond_dim,
647
- phys_dim=phys_dim,
648
- dtype=dtype,
649
- cyclic=cyclic,
650
- trans_invar=trans_invar,
651
- )
652
- return mps.to_dense()
653
-
654
-
655
- rand_mps = rand_matrix_product_state
656
-
657
-
658
- @random_seed_fn
659
- def rand_seperable(dims, num_mix=10, dtype=complex):
660
- """Generate a random, mixed, seperable state. E.g rand_seperable([2, 2])
661
- for a mixed two qubit state with no entanglement.
662
-
663
- Parameters
664
- ----------
665
- dims : tuple of int
666
- The local dimensions across which to be seperable.
667
- num_mix : int, optional
668
- How many individual product states to sum together, each with
669
- random weight.
670
-
671
- Returns
672
- -------
673
- qarray
674
- Mixed seperable state.
675
- """
676
-
677
- def gen_single_sites():
678
- for dim in dims:
679
- yield rand_rho(dim, dtype=dtype)
680
-
681
- weights = rand(num_mix)
682
-
683
- def gen_single_states():
684
- for w in weights:
685
- yield w * kron(*gen_single_sites())
686
-
687
- return sum(gen_single_states()) / np.sum(weights)
688
-
689
-
690
- @random_seed_fn
691
- def rand_iso(n, m, dtype=complex):
692
- """Generate a random isometry of shape ``(n, m)``."""
693
- data = randn((n, m), dtype=dtype)
694
-
695
- q, _ = np.linalg.qr(data if n >= m else data.T)
696
- q = q.astype(dtype)
697
-
698
- return q if (n >= m) else q.T
699
-
700
-
701
- @random_seed_fn
702
- def rand_mera(n, invariant=False, dtype=complex):
703
- """Generate a random mera state of ``n`` qubits, which must be a power
704
- of 2. This uses ``quimb.tensor``.
705
- """
706
- import quimb.tensor as qt
707
-
708
- if invariant:
709
- constructor = qt.MERA.rand_invar
710
- else:
711
- constructor = qt.MERA.rand
712
-
713
- return constructor(n, dtype=dtype).to_qarray()