# Generating Objects ## States - {func}`~quimb.gen.states.basis_vec` - {func}`~quimb.gen.states.up` - {func}`~quimb.gen.states.down` - {func}`~quimb.gen.states.plus` - {func}`~quimb.gen.states.minus` - {func}`~quimb.gen.states.yplus` - {func}`~quimb.gen.states.yminus` - {func}`~quimb.gen.states.bloch_state` - {func}`~quimb.gen.states.bell_state` - {func}`~quimb.gen.states.singlet` - {func}`~quimb.gen.states.thermal_state` - {func}`~quimb.gen.states.computational_state` - {func}`~quimb.gen.states.neel_state` - {func}`~quimb.gen.states.singlet_pairs` - {func}`~quimb.gen.states.werner_state` - {func}`~quimb.gen.states.ghz_state` - {func}`~quimb.gen.states.w_state` - {func}`~quimb.gen.states.levi_civita` - {func}`~quimb.gen.states.perm_state` - {func}`~quimb.gen.states.graph_state_1d` ## Operators **Gate operators**: - {func}`~quimb.gen.operators.pauli` - {func}`~quimb.gen.operators.hadamard` - {func}`~quimb.gen.operators.phase_gate` - {func}`~quimb.gen.operators.T_gate` - {func}`~quimb.gen.operators.S_gate` - {func}`~quimb.gen.operators.U_gate` - {func}`~quimb.gen.operators.rotation` - {func}`~quimb.gen.operators.Rx` - {func}`~quimb.gen.operators.Ry` - {func}`~quimb.gen.operators.Rz` - {func}`~quimb.gen.operators.Xsqrt` - {func}`~quimb.gen.operators.Ysqrt` - {func}`~quimb.gen.operators.Zsqrt` - {func}`~quimb.gen.operators.Wsqrt` - {func}`~quimb.gen.operators.phase_gate` - {func}`~quimb.gen.operators.swap` - {func}`~quimb.gen.operators.iswap` - {func}`~quimb.gen.operators.fsim` - {func}`~quimb.gen.operators.fsimg` - {func}`~quimb.gen.operators.controlled` - {func}`~quimb.gen.operators.CNOT` - {func}`~quimb.gen.operators.cX` - {func}`~quimb.gen.operators.cY` - {func}`~quimb.gen.operators.cZ` Most of these are cached (and immutable), so can be called repeatedly without creating any new objects: ```python >>> pauli('Z') is pauli('Z') True ``` **Hamiltonians and related operators**: - {func}`~quimb.gen.operators.spin_operator` - {func}`~quimb.gen.operators.ham_heis` - {func}`~quimb.gen.operators.ham_heis_2D` - {func}`~quimb.gen.operators.ham_ising` - {func}`~quimb.gen.operators.ham_XY` - {func}`~quimb.gen.operators.ham_XXZ` - {func}`~quimb.gen.operators.ham_j1j2` - {func}`~quimb.gen.operators.ham_mbl` - {func}`~quimb.gen.operators.zspin_projector` - {func}`~quimb.gen.operators.create` - {func}`~quimb.gen.operators.destroy` - {func}`~quimb.gen.operators.num` - {func}`~quimb.gen.operators.ham_hubbard_hardcore` :::{note} The Hamiltonians are generally defined using spin operators rather than Pauli matrices. Thus for example, the following spin-1/2 Hamiltonians would be equivalent - in spin-operators: $$ \hat{H} = \sum J S^X_i S^X_{i + 1} + B S^Z_i $$ - and in Pauli operators (with $S^X=\dfrac{\sigma^X}{2}$ etc.): $$ \hat{H} = \sum \dfrac{J}{4} \sigma^X_i \sigma^X_{i + 1} + \dfrac{B}{2} \sigma^Z_{i} $$ note that interaction terms are scaled different than the single site terms. ::: ## Random States & Operators **Random pure states**: - {func}`~quimb.gen.rand.rand_ket` - {func}`~quimb.gen.rand.rand_haar_state` - {func}`~quimb.gen.rand.gen_rand_haar_states` - {func}`~quimb.gen.rand.rand_product_state` - {func}`~quimb.gen.rand.rand_matrix_product_state` - {func}`~quimb.gen.rand.rand_mera` **Random operators**: - {func}`~quimb.gen.rand.rand_matrix` - {func}`~quimb.gen.rand.rand_herm` - {func}`~quimb.gen.rand.rand_pos` - {func}`~quimb.gen.rand.rand_rho` - {func}`~quimb.gen.rand.rand_uni` - {func}`~quimb.gen.rand.rand_mix` - {func}`~quimb.gen.rand.rand_seperable` - {func}`~quimb.gen.rand.rand_iso` All of these functions accept a `seed` argument for replicability: ```python >>> rand_rho(2, seed=42) qarray([[ 0.196764+7.758223e-19j, -0.08442 +2.133635e-01j], [-0.08442 -2.133635e-01j, 0.803236-2.691589e-18j]]) >>> rand_rho(2, seed=42) qarray([[ 0.196764+7.758223e-19j, -0.08442 +2.133635e-01j], [-0.08442 -2.133635e-01j, 0.803236-2.691589e-18j]]) ``` For some applications, generating random numbers with a single thread can be a bottleneck, though since version 1.17 `numpy` itself enables parallel streams of random numbers to be generated. `quimb` handles setting up the bit generators and multi-threading the creation of random arrays, with potentially large performance gains. While the random number sequences can be still replicated using the `seed` argument, they also depend (deterministically) on the number of threads used, so may vary across machines unless this is set (e.g. with `'OMP_NUM_THREADS'`). :::{note} Previously, [randomgen](https://github.com/bashtage/randomgen) was needed for this functionality, and its [bit generators](https://bashtage.github.io/randomgen/bit_generators/index.html) can still be specified to {func}`~quimb.gen.rand.set_rand_bitgen` if installed. ::: The following gives a quick idea of the speed-ups possible. First random, complex, normally distributed array generation with a naive `numpy` method: ```python >>> import numpy as np >>> %timeit np.random.randn(2**22) + 1j * np.random.randn(2**22) 394 ms ± 2.93 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) ``` And generation with `quimb`: ```python >>> import quimb as qu >>> %timeit qu.randn(2**22, dtype=complex) 45.8 ms ± 2.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> # try a randomgen bit generator >>> qu.set_rand_bitgen('Xoshiro256') >>> %timeit qu.randn(2**22, dtype=complex) 41.2 ms ± 2.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> # use the default numpy bit generator >>> qu.set_rand_bitgen(None) ```