or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdoperators.mdphase-space.mdprocess-tomography.mdquantum-gates.mdquantum-information.mdquantum-objects.mdrandom-objects.mdsolvers.mdstates.mdsuperoperators.mdtensor-operations.mdutilities.mdvisualization.md

phase-space.mddocs/

0

# Phase Space Functions

1

2

Phase space representations and quasi-probability distributions for continuous variable quantum systems.

3

4

## Capabilities

5

6

### Wigner Function

7

8

Calculate and manipulate Wigner functions for quantum states.

9

10

```python { .api }

11

def wigner(rho: Qobj, xvec: ArrayLike, yvec: ArrayLike, g: float = np.sqrt(2),

12

sparse: bool = False, method: str = 'clenshaw') -> np.ndarray:

13

"""

14

Calculate Wigner function on phase space grid.

15

16

Parameters:

17

- rho: Density matrix or state vector

18

- xvec: Array of x-coordinates (position-like)

19

- yvec: Array of y-coordinates (momentum-like)

20

- g: Scaling factor (default √2)

21

- sparse: Use sparse matrices

22

- method: 'clenshaw', 'iterative', or 'laguerre'

23

24

Returns:

25

- ndarray: Wigner function W(x,y) on grid

26

"""

27

28

def wigner_transform(psi: Qobj, op: Qobj, g: float = np.sqrt(2)) -> Qobj:

29

"""

30

Calculate Wigner transform of operator with respect to state.

31

32

Parameters:

33

- psi: Reference state

34

- op: Operator to transform

35

- g: Scaling factor

36

37

Returns:

38

- Qobj: Wigner-transformed operator

39

"""

40

```

41

42

### Q-Function (Husimi Distribution)

43

44

Calculate Q-function and related phase space distributions.

45

46

```python { .api }

47

def qfunc(rho: Qobj, xvec: ArrayLike, yvec: ArrayLike, g: float = np.sqrt(2),

48

sparse: bool = False) -> np.ndarray:

49

"""

50

Calculate Q-function (Husimi distribution) on phase space grid.

51

52

Parameters:

53

- rho: Density matrix or state vector

54

- xvec: Array of x-coordinates

55

- yvec: Array of y-coordinates

56

- g: Scaling factor (default √2)

57

- sparse: Use sparse matrices

58

59

Returns:

60

- ndarray: Q-function Q(α) = ⟨α|ρ|α⟩/π on grid

61

"""

62

63

class QFunc:

64

"""

65

Q-function calculation class for efficient repeated calculations.

66

"""

67

def __init__(self, rho: Qobj = None, xvec: ArrayLike = None, yvec: ArrayLike = None):

68

"""

69

Initialize Q-function calculator.

70

71

Parameters:

72

- rho: Density matrix

73

- xvec: X-coordinate array

74

- yvec: Y-coordinate array

75

"""

76

77

def qfunc(self, rho: Qobj = None) -> np.ndarray:

78

"""

79

Calculate Q-function for given or stored state.

80

81

Parameters:

82

- rho: Density matrix (uses stored if None)

83

84

Returns:

85

- ndarray: Q-function values

86

"""

87

```

88

89

### Spin Phase Space Functions

90

91

Phase space representations for spin systems.

92

93

```python { .api }

94

def spin_wigner(rho: Qobj, theta: ArrayLike, phi: ArrayLike) -> np.ndarray:

95

"""

96

Calculate spin Wigner function on sphere.

97

98

Parameters:

99

- rho: Spin density matrix

100

- theta: Polar angle array (0 to π)

101

- phi: Azimuthal angle array (0 to 2π)

102

103

Returns:

104

- ndarray: Spin Wigner function on sphere

105

"""

106

107

def spin_q_function(rho: Qobj, theta: ArrayLike, phi: ArrayLike) -> np.ndarray:

108

"""

109

Calculate spin Q-function on sphere.

110

111

Parameters:

112

- rho: Spin density matrix

113

- theta: Polar angle array

114

- phi: Azimuthal angle array

115

116

Returns:

117

- ndarray: Spin Q-function on sphere

118

"""

119

```

120

121

### Usage Examples

122

123

```python

124

import qutip as qt

125

import numpy as np

126

import matplotlib.pyplot as plt

127

128

# Phase space grid

129

x_max = 4

130

N_points = 100

131

xvec = np.linspace(-x_max, x_max, N_points)

132

yvec = np.linspace(-x_max, x_max, N_points)

133

134

# Various quantum states for Wigner function analysis

135

136

# 1. Vacuum state

137

N_levels = 20

138

vacuum = qt.basis(N_levels, 0)

139

rho_vacuum = vacuum * vacuum.dag()

140

141

W_vacuum = qt.wigner(rho_vacuum, xvec, yvec)

142

print(f"Vacuum Wigner function:")

143

print(f" Min value: {W_vacuum.min():.3f}")

144

print(f" Max value: {W_vacuum.max():.3f}")

145

print(f" Should be Gaussian with max ≈ 0.318")

146

147

# 2. Coherent state

148

alpha = 1.5 + 1.0j

149

coherent = qt.coherent(N_levels, alpha)

150

rho_coherent = coherent * coherent.dag()

151

152

W_coherent = qt.wigner(rho_coherent, xvec, yvec)

153

Q_coherent = qt.qfunc(rho_coherent, xvec, yvec)

154

155

print(f"Coherent state α = {alpha}:")

156

print(f" Wigner min/max: [{W_coherent.min():.3f}, {W_coherent.max():.3f}]")

157

print(f" Q-function min/max: [{Q_coherent.min():.3f}, {Q_coherent.max():.3f}]")

158

159

# Find peak positions

160

X, Y = np.meshgrid(xvec, yvec)

161

max_idx = np.unravel_index(np.argmax(W_coherent), W_coherent.shape)

162

x_peak, y_peak = xvec[max_idx[1]], yvec[max_idx[0]]

163

print(f" Peak at (x,p) ≈ ({x_peak:.2f}, {y_peak:.2f})")

164

print(f" Expected: ({np.sqrt(2)*alpha.real:.2f}, {np.sqrt(2)*alpha.imag:.2f})")

165

166

# 3. Squeezed state

167

squeeze_param = 0.8

168

squeezed = qt.squeeze(N_levels, squeeze_param) * vacuum

169

rho_squeezed = squeezed * squeezed.dag()

170

171

W_squeezed = qt.wigner(rho_squeezed, xvec, yvec)

172

print(f"Squeezed vacuum (r={squeeze_param}):")

173

print(f" Wigner min/max: [{W_squeezed.min():.3f}, {W_squeezed.max():.3f}]")

174

175

# 4. Fock state (non-classical)

176

n_photons = 2

177

fock = qt.basis(N_levels, n_photons)

178

rho_fock = fock * fock.dag()

179

180

W_fock = qt.wigner(rho_fock, xvec, yvec)

181

Q_fock = qt.qfunc(rho_fock, xvec, yvec)

182

183

print(f"Fock state |{n_photons}⟩:")

184

print(f" Wigner min/max: [{W_fock.min():.3f}, {W_fock.max():.3f}]")

185

print(f" Has negative values: {W_fock.min() < -1e-10}") # Non-classical

186

print(f" Q-function is always ≥ 0: {Q_fock.min() >= -1e-10}")

187

188

# 5. Cat state (superposition)

189

cat_amp = 1.5

190

cat_state = (qt.coherent(N_levels, cat_amp) + qt.coherent(N_levels, -cat_amp)).unit()

191

rho_cat = cat_state * cat_state.dag()

192

193

W_cat = qt.wigner(rho_cat, xvec, yvec)

194

print(f"Schrödinger cat state (α = ±{cat_amp}):")

195

print(f" Wigner min/max: [{W_cat.min():.3f}, {W_cat.max():.3f}]")

196

print(f" Exhibits interference fringes with negative values")

197

198

# 6. Thermal state

199

n_thermal = 1.5

200

rho_thermal = qt.thermal_dm(N_levels, n_thermal)

201

202

W_thermal = qt.wigner(rho_thermal, xvec, yvec)

203

Q_thermal = qt.qfunc(rho_thermal, xvec, yvec)

204

205

print(f"Thermal state (⟨n⟩ = {n_thermal}):")

206

print(f" Wigner min/max: [{W_thermal.min():.3f}, {W_thermal.max():.3f}]")

207

print(f" Q-function max: {Q_thermal.max():.3f}")

208

209

# Comparison of calculation methods

210

# Different methods for Wigner function calculation

211

W_clenshaw = qt.wigner(rho_coherent, xvec, yvec, method='clenshaw')

212

W_iterative = qt.wigner(rho_coherent, xvec, yvec, method='iterative')

213

214

method_diff = np.abs(W_clenshaw - W_iterative).max()

215

print(f"Clenshaw vs iterative method difference: {method_diff:.2e}")

216

217

# Spin Wigner functions

218

# Spin-1/2 system

219

j = 0.5

220

theta = np.linspace(0, np.pi, 50)

221

phi = np.linspace(0, 2*np.pi, 100)

222

223

# Spin-up state

224

spin_up = qt.spin_state(j, j) # |j,j⟩ = |1/2,1/2⟩

225

rho_spin_up = spin_up * spin_up.dag()

226

227

W_spin_up = qt.spin_wigner(rho_spin_up, theta, phi)

228

Q_spin_up = qt.spin_q_function(rho_spin_up, theta, phi)

229

230

print(f"Spin-up Wigner function:")

231

print(f" Min/max: [{W_spin_up.min():.3f}, {W_spin_up.max():.3f}]")

232

print(f" Peak should be at north pole (θ=0)")

233

234

# Spin coherent state

235

theta_coherent, phi_coherent = np.pi/3, np.pi/4 # Pointing direction

236

spin_coherent = qt.spin_coherent(j, theta_coherent, phi_coherent)

237

rho_spin_coherent = spin_coherent * spin_coherent.dag()

238

239

W_spin_coherent = qt.spin_wigner(rho_spin_coherent, theta, phi)

240

print(f"Spin coherent state:")

241

print(f" Direction: θ={theta_coherent:.2f}, φ={phi_coherent:.2f}")

242

print(f" Wigner min/max: [{W_spin_coherent.min():.3f}, {W_spin_coherent.max():.3f}]")

243

244

# Spin-1 system (larger)

245

j1 = 1.0

246

spin_states_j1 = [qt.spin_state(j1, m) for m in [1, 0, -1]] # |1,1⟩, |1,0⟩, |1,-1⟩

247

248

# Superposition state

249

superpos_j1 = (spin_states_j1[0] + spin_states_j1[2]).unit() # (|1,1⟩ + |1,-1⟩)/√2

250

rho_superpos_j1 = superpos_j1 * superpos_j1.dag()

251

252

W_superpos_j1 = qt.spin_wigner(rho_superpos_j1, theta, phi)

253

print(f"Spin-1 superposition state:")

254

print(f" Wigner min/max: [{W_superpos_j1.min():.3f}, {W_superpos_j1.max():.3f}]")

255

256

# Phase space integral properties

257

# Wigner function should integrate to 1

258

X, Y = np.meshgrid(xvec, yvec)

259

dx = xvec[1] - xvec[0]

260

dy = yvec[1] - yvec[0]

261

262

integral_W_vacuum = np.sum(W_vacuum) * dx * dy / np.pi

263

integral_W_coherent = np.sum(W_coherent) * dx * dy / np.pi

264

integral_Q_coherent = np.sum(Q_coherent) * dx * dy / np.pi

265

266

print(f"Phase space integrals (should be 1):")

267

print(f" Vacuum Wigner: {integral_W_vacuum:.3f}")

268

print(f" Coherent Wigner: {integral_W_coherent:.3f}")

269

print(f" Coherent Q-function: {integral_Q_coherent:.3f}")

270

271

# Q-function class usage

272

qfunc_calc = qt.QFunc(rho_coherent, xvec, yvec)

273

Q_from_class = qfunc_calc.qfunc()

274

275

# Verify consistency

276

consistency_check = np.abs(Q_from_class - Q_coherent).max()

277

print(f"Q-function class consistency: {consistency_check:.2e}")

278

279

# Time evolution in phase space

280

# Harmonic oscillator evolution

281

H = qt.num(N_levels) # Number operator

282

times = np.linspace(0, 2*np.pi, 5) # One period

283

284

print(f"Time evolution of coherent state:")

285

for i, t in enumerate(times):

286

# Evolve state

287

U = (-1j * H * t).expm()

288

psi_t = U * coherent

289

rho_t = psi_t * psi_t.dag()

290

291

# Calculate Wigner function

292

W_t = qt.wigner(rho_t, xvec, yvec)

293

294

# Find peak

295

max_idx = np.unravel_index(np.argmax(W_t), W_t.shape)

296

x_peak, y_peak = xvec[max_idx[1]], yvec[max_idx[0]]

297

298

print(f" t = {t:.2f}: peak at ({x_peak:.2f}, {y_peak:.2f})")

299

300

# The coherent state should rotate in phase space with frequency ω=1

301

# Expected position: α(t) = α * exp(-iωt) = α * exp(-it)

302

alpha_expected = alpha * np.exp(-1j * times[-1])

303

x_expected = np.sqrt(2) * alpha_expected.real

304

y_expected = np.sqrt(2) * alpha_expected.imag

305

print(f" Expected final position: ({x_expected:.2f}, {y_expected:.2f})")

306

307

# Visualization example (pseudo-code, actual plotting would need matplotlib)

308

def plot_phase_space_comparison(states_dict, xvec, yvec):

309

"""

310

Example function showing how to visualize phase space functions.

311

"""

312

print("Phase space visualization:")

313

for name, rho in states_dict.items():

314

W = qt.wigner(rho, xvec, yvec)

315

Q = qt.qfunc(rho, xvec, yvec)

316

317

print(f" {name}:")

318

print(f" Wigner: min={W.min():.3f}, max={W.max():.3f}")

319

print(f" Q-func: min={Q.min():.3f}, max={Q.max():.3f}")

320

print(f" Non-classical (W<0): {W.min() < -1e-10}")

321

322

# Example usage

323

states_to_plot = {

324

'Vacuum': rho_vacuum,

325

'Coherent': rho_coherent,

326

'Squeezed': rho_squeezed,

327

'Fock n=2': rho_fock,

328

'Cat state': rho_cat,

329

'Thermal': rho_thermal

330

}

331

332

plot_phase_space_comparison(states_to_plot, xvec, yvec)

333

```

334

335

## Types

336

337

```python { .api }

338

# Phase space functions return numpy ndarrays containing

339

# the calculated quasi-probability distributions on the specified grids

340

```