guohanghui commited on
Commit
a00890d
·
verified ·
1 Parent(s): c054109

Update qutip/mcp_output/mcp_plugin/mcp_service.py

Browse files
qutip/mcp_output/mcp_plugin/mcp_service.py CHANGED
@@ -1,5 +1,6 @@
1
  import os
2
  import sys
 
3
 
4
  # Add the local source directory to sys.path
5
  source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
@@ -7,45 +8,912 @@ if source_path not in sys.path:
7
  sys.path.insert(0, source_path)
8
 
9
  from fastmcp import FastMCP
10
- from qutip.visualization import plot_wigner, plot_fock_distribution
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  # Create the FastMCP service application
13
- mcp = FastMCP("quantum_visualization_service")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  @mcp.tool(name="plot_wigner_tool", description="Plot the Wigner function of a quantum state.")
16
- def plot_wigner_tool(state: 'Qobj') -> dict:
17
  """
18
  Plots the Wigner function for a given quantum state.
19
 
20
  Parameters:
21
- - state (Qobj): The quantum state for which to plot the Wigner function.
 
 
22
 
23
  Returns:
24
  - dict: A dictionary containing the success status and result or error message.
25
  """
26
  try:
 
 
 
 
 
 
 
 
 
27
  plot_wigner(state)
28
  return {"success": True, "result": "Wigner plot generated successfully."}
29
  except Exception as e:
30
  return {"success": False, "error": str(e)}
31
 
 
32
  @mcp.tool(name="plot_fock_distribution_tool", description="Plot the Fock distribution of a quantum state.")
33
- def plot_fock_distribution_tool(state: 'Qobj') -> dict:
34
  """
35
  Plots the Fock distribution for a given quantum state.
36
 
37
  Parameters:
38
- - state (Qobj): The quantum state for which to plot the Fock distribution.
 
 
39
 
40
  Returns:
41
  - dict: A dictionary containing the success status and result or error message.
42
  """
43
  try:
 
 
 
 
 
 
 
 
 
44
  plot_fock_distribution(state)
45
  return {"success": True, "result": "Fock distribution plot generated successfully."}
46
  except Exception as e:
47
  return {"success": False, "error": str(e)}
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def create_app() -> FastMCP:
50
  """
51
  Creates and returns the FastMCP instance for the service.
 
1
  import os
2
  import sys
3
+ from typing import List, Optional
4
 
5
  # Add the local source directory to sys.path
6
  source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
 
8
  sys.path.insert(0, source_path)
9
 
10
  from fastmcp import FastMCP
11
+ import numpy as np
12
+
13
+ # Import QuTiP modules
14
+ from qutip import (
15
+ # States
16
+ basis, fock, fock_dm, coherent, coherent_dm, thermal_dm,
17
+ ket2dm, bell_state, ghz_state, w_state, spin_state, spin_coherent,
18
+ # Operators
19
+ destroy, create, num, qeye, sigmax, sigmay, sigmaz, sigmap, sigmam,
20
+ jmat, squeeze, displace, qdiags,
21
+ # Tensor operations
22
+ tensor, expect, variance,
23
+ # Metrics
24
+ fidelity, tracedist,
25
+ # Entropy
26
+ entropy_vn, entropy_linear, concurrence, negativity,
27
+ # Wigner
28
+ wigner, qfunc,
29
+ # Random
30
+ rand_ket, rand_dm, rand_unitary, rand_herm,
31
+ # Visualization
32
+ Qobj,
33
+ )
34
+ from qutip.visualization import (
35
+ plot_wigner, plot_fock_distribution, hinton, matrix_histogram,
36
+ plot_energy_levels, plot_expectation_values
37
+ )
38
 
39
  # Create the FastMCP service application
40
+ mcp = FastMCP("qutip_quantum_service")
41
+
42
+
43
+ # ==================== Quantum States ====================
44
+
45
+ @mcp.tool(name="create_basis_state", description="Create a Fock state |n> in an N-dimensional Hilbert space.")
46
+ def create_basis_state(N: int, n: int = 0) -> dict:
47
+ """
48
+ Creates a Fock state (number state) |n> in an N-dimensional Hilbert space.
49
+
50
+ Parameters:
51
+ - N (int): Number of basis states in the Hilbert space.
52
+ - n (int): The number state index (default: 0 for ground state).
53
+
54
+ Returns:
55
+ - dict: Contains the state data or error message.
56
+ """
57
+ try:
58
+ state = basis(N, n)
59
+ return {
60
+ "success": True,
61
+ "state_type": state.type,
62
+ "dims": str(state.dims),
63
+ "shape": str(state.shape),
64
+ "data": state.full().tolist()
65
+ }
66
+ except Exception as e:
67
+ return {"success": False, "error": str(e)}
68
+
69
+
70
+ @mcp.tool(name="create_coherent_state", description="Create a coherent state with eigenvalue alpha.")
71
+ def create_coherent_state(N: int, alpha_real: float, alpha_imag: float = 0.0) -> dict:
72
+ """
73
+ Creates a coherent state |alpha> in an N-dimensional Hilbert space.
74
+
75
+ Parameters:
76
+ - N (int): Number of Fock states in Hilbert space.
77
+ - alpha_real (float): Real part of the coherent state eigenvalue.
78
+ - alpha_imag (float): Imaginary part of the coherent state eigenvalue.
79
+
80
+ Returns:
81
+ - dict: Contains the state data or error message.
82
+ """
83
+ try:
84
+ alpha = complex(alpha_real, alpha_imag)
85
+ state = coherent(N, alpha)
86
+ return {
87
+ "success": True,
88
+ "alpha": str(alpha),
89
+ "state_type": state.type,
90
+ "dims": str(state.dims),
91
+ "shape": str(state.shape),
92
+ "mean_photon_number": float(expect(num(N), state).real)
93
+ }
94
+ except Exception as e:
95
+ return {"success": False, "error": str(e)}
96
+
97
+
98
+ @mcp.tool(name="create_thermal_state", description="Create a thermal density matrix with given average photon number.")
99
+ def create_thermal_state(N: int, n_avg: float) -> dict:
100
+ """
101
+ Creates a thermal state density matrix.
102
+
103
+ Parameters:
104
+ - N (int): Number of basis states in Hilbert space.
105
+ - n_avg (float): Average photon number (temperature parameter).
106
+
107
+ Returns:
108
+ - dict: Contains the state data or error message.
109
+ """
110
+ try:
111
+ state = thermal_dm(N, n_avg)
112
+ return {
113
+ "success": True,
114
+ "n_avg": n_avg,
115
+ "state_type": state.type,
116
+ "dims": str(state.dims),
117
+ "shape": str(state.shape),
118
+ "purity": float((state * state).tr().real)
119
+ }
120
+ except Exception as e:
121
+ return {"success": False, "error": str(e)}
122
+
123
+
124
+ @mcp.tool(name="create_bell_state", description="Create a Bell state for two qubits.")
125
+ def create_bell_state(state_type: str = "00") -> dict:
126
+ """
127
+ Creates one of the four Bell states.
128
+
129
+ Parameters:
130
+ - state_type (str): Type of Bell state - "00", "01", "10", or "11".
131
+
132
+ Returns:
133
+ - dict: Contains the state data or error message.
134
+ """
135
+ try:
136
+ state = bell_state(state_type)
137
+ return {
138
+ "success": True,
139
+ "bell_state_type": state_type,
140
+ "state_type": state.type,
141
+ "dims": str(state.dims),
142
+ "shape": str(state.shape),
143
+ "data": state.full().tolist()
144
+ }
145
+ except Exception as e:
146
+ return {"success": False, "error": str(e)}
147
+
148
+
149
+ @mcp.tool(name="create_ghz_state", description="Create a GHZ (Greenberger-Horne-Zeilinger) state for N qubits.")
150
+ def create_ghz_state(N: int) -> dict:
151
+ """
152
+ Creates a GHZ state for N qubits: (|00...0> + |11...1>)/sqrt(2).
153
+
154
+ Parameters:
155
+ - N (int): Number of qubits.
156
+
157
+ Returns:
158
+ - dict: Contains the state data or error message.
159
+ """
160
+ try:
161
+ state = ghz_state(N)
162
+ return {
163
+ "success": True,
164
+ "n_qubits": N,
165
+ "state_type": state.type,
166
+ "dims": str(state.dims),
167
+ "shape": str(state.shape)
168
+ }
169
+ except Exception as e:
170
+ return {"success": False, "error": str(e)}
171
+
172
+
173
+ @mcp.tool(name="create_spin_coherent_state", description="Create a spin coherent state.")
174
+ def create_spin_coherent_state(j: float, theta: float, phi: float) -> dict:
175
+ """
176
+ Creates a spin coherent state.
177
+
178
+ Parameters:
179
+ - j (float): Spin quantum number (e.g., 0.5, 1, 1.5, ...).
180
+ - theta (float): Polar angle (0 to pi).
181
+ - phi (float): Azimuthal angle (0 to 2*pi).
182
+
183
+ Returns:
184
+ - dict: Contains the state data or error message.
185
+ """
186
+ try:
187
+ state = spin_coherent(j, theta, phi)
188
+ return {
189
+ "success": True,
190
+ "j": j,
191
+ "theta": theta,
192
+ "phi": phi,
193
+ "state_type": state.type,
194
+ "dims": str(state.dims),
195
+ "shape": str(state.shape)
196
+ }
197
+ except Exception as e:
198
+ return {"success": False, "error": str(e)}
199
+
200
+
201
+ # ==================== Quantum Operators ====================
202
+
203
+ @mcp.tool(name="create_annihilation_operator", description="Create a bosonic annihilation (lowering) operator.")
204
+ def create_annihilation_operator(N: int) -> dict:
205
+ """
206
+ Creates a destruction (annihilation) operator for an N-dimensional Hilbert space.
207
+
208
+ Parameters:
209
+ - N (int): Number of basis states in Hilbert space.
210
+
211
+ Returns:
212
+ - dict: Contains the operator data or error message.
213
+ """
214
+ try:
215
+ op = destroy(N)
216
+ return {
217
+ "success": True,
218
+ "operator_type": op.type,
219
+ "dims": str(op.dims),
220
+ "shape": str(op.shape),
221
+ "is_hermitian": bool(op.isherm),
222
+ "data": op.full().tolist()
223
+ }
224
+ except Exception as e:
225
+ return {"success": False, "error": str(e)}
226
+
227
+
228
+ @mcp.tool(name="create_creation_operator", description="Create a bosonic creation (raising) operator.")
229
+ def create_creation_operator(N: int) -> dict:
230
+ """
231
+ Creates a creation (raising) operator for an N-dimensional Hilbert space.
232
+
233
+ Parameters:
234
+ - N (int): Number of basis states in Hilbert space.
235
+
236
+ Returns:
237
+ - dict: Contains the operator data or error message.
238
+ """
239
+ try:
240
+ op = create(N)
241
+ return {
242
+ "success": True,
243
+ "operator_type": op.type,
244
+ "dims": str(op.dims),
245
+ "shape": str(op.shape),
246
+ "is_hermitian": bool(op.isherm),
247
+ "data": op.full().tolist()
248
+ }
249
+ except Exception as e:
250
+ return {"success": False, "error": str(e)}
251
+
252
+
253
+ @mcp.tool(name="create_number_operator", description="Create a photon number operator.")
254
+ def create_number_operator(N: int) -> dict:
255
+ """
256
+ Creates a number operator for an N-dimensional Hilbert space.
257
+
258
+ Parameters:
259
+ - N (int): Number of basis states in Hilbert space.
260
+
261
+ Returns:
262
+ - dict: Contains the operator data or error message.
263
+ """
264
+ try:
265
+ op = num(N)
266
+ return {
267
+ "success": True,
268
+ "operator_type": op.type,
269
+ "dims": str(op.dims),
270
+ "shape": str(op.shape),
271
+ "is_hermitian": bool(op.isherm),
272
+ "data": op.full().tolist()
273
+ }
274
+ except Exception as e:
275
+ return {"success": False, "error": str(e)}
276
+
277
+
278
+ @mcp.tool(name="create_pauli_operator", description="Create a Pauli spin-1/2 operator (x, y, or z).")
279
+ def create_pauli_operator(which: str) -> dict:
280
+ """
281
+ Creates a Pauli spin-1/2 operator.
282
+
283
+ Parameters:
284
+ - which (str): Which Pauli operator - "x", "y", or "z".
285
+
286
+ Returns:
287
+ - dict: Contains the operator data or error message.
288
+ """
289
+ try:
290
+ if which.lower() == "x":
291
+ op = sigmax()
292
+ elif which.lower() == "y":
293
+ op = sigmay()
294
+ elif which.lower() == "z":
295
+ op = sigmaz()
296
+ else:
297
+ return {"success": False, "error": "Invalid Pauli operator. Use 'x', 'y', or 'z'."}
298
+
299
+ return {
300
+ "success": True,
301
+ "pauli_type": which,
302
+ "operator_type": op.type,
303
+ "dims": str(op.dims),
304
+ "shape": str(op.shape),
305
+ "is_hermitian": bool(op.isherm),
306
+ "data": op.full().tolist()
307
+ }
308
+ except Exception as e:
309
+ return {"success": False, "error": str(e)}
310
+
311
+
312
+ @mcp.tool(name="create_spin_operator", description="Create a spin-j operator (Jx, Jy, Jz, J+, or J-).")
313
+ def create_spin_operator(j: float, which: str) -> dict:
314
+ """
315
+ Creates a spin-j angular momentum operator.
316
+
317
+ Parameters:
318
+ - j (float): Spin quantum number (e.g., 0.5, 1, 1.5, ...).
319
+ - which (str): Which operator - "x", "y", "z", "+", or "-".
320
+
321
+ Returns:
322
+ - dict: Contains the operator data or error message.
323
+ """
324
+ try:
325
+ op = jmat(j, which)
326
+ return {
327
+ "success": True,
328
+ "j": j,
329
+ "which": which,
330
+ "operator_type": op.type,
331
+ "dims": str(op.dims),
332
+ "shape": str(op.shape),
333
+ "is_hermitian": bool(op.isherm),
334
+ "data": op.full().tolist()
335
+ }
336
+ except Exception as e:
337
+ return {"success": False, "error": str(e)}
338
+
339
+
340
+ @mcp.tool(name="create_displacement_operator", description="Create a displacement operator for coherent states.")
341
+ def create_displacement_operator(N: int, alpha_real: float, alpha_imag: float = 0.0) -> dict:
342
+ """
343
+ Creates a displacement operator D(alpha).
344
+
345
+ Parameters:
346
+ - N (int): Number of Fock states in Hilbert space.
347
+ - alpha_real (float): Real part of displacement amplitude.
348
+ - alpha_imag (float): Imaginary part of displacement amplitude.
349
+
350
+ Returns:
351
+ - dict: Contains the operator data or error message.
352
+ """
353
+ try:
354
+ alpha = complex(alpha_real, alpha_imag)
355
+ op = displace(N, alpha)
356
+ return {
357
+ "success": True,
358
+ "alpha": str(alpha),
359
+ "operator_type": op.type,
360
+ "dims": str(op.dims),
361
+ "shape": str(op.shape),
362
+ "is_unitary": bool(op.isunitary)
363
+ }
364
+ except Exception as e:
365
+ return {"success": False, "error": str(e)}
366
+
367
+
368
+ @mcp.tool(name="create_squeeze_operator", description="Create a squeezing operator.")
369
+ def create_squeeze_operator(N: int, z_real: float, z_imag: float = 0.0) -> dict:
370
+ """
371
+ Creates a squeezing operator S(z).
372
+
373
+ Parameters:
374
+ - N (int): Number of Fock states in Hilbert space.
375
+ - z_real (float): Real part of squeezing parameter.
376
+ - z_imag (float): Imaginary part of squeezing parameter.
377
+
378
+ Returns:
379
+ - dict: Contains the operator data or error message.
380
+ """
381
+ try:
382
+ z = complex(z_real, z_imag)
383
+ op = squeeze(N, z)
384
+ return {
385
+ "success": True,
386
+ "z": str(z),
387
+ "operator_type": op.type,
388
+ "dims": str(op.dims),
389
+ "shape": str(op.shape),
390
+ "is_unitary": bool(op.isunitary)
391
+ }
392
+ except Exception as e:
393
+ return {"success": False, "error": str(e)}
394
+
395
+
396
+ # ==================== Measurements & Expectations ====================
397
+
398
+ @mcp.tool(name="calculate_expectation_value", description="Calculate the expectation value of an operator for a given state.")
399
+ def calculate_expectation_value(N: int, state_n: int, operator_type: str) -> dict:
400
+ """
401
+ Calculates the expectation value <state|operator|state>.
402
+
403
+ Parameters:
404
+ - N (int): Hilbert space dimension.
405
+ - state_n (int): Fock state index.
406
+ - operator_type (str): Type of operator - "number", "x", "p" (position/momentum for harmonic oscillator).
407
+
408
+ Returns:
409
+ - dict: Contains the expectation value or error message.
410
+ """
411
+ try:
412
+ state = basis(N, state_n)
413
+
414
+ if operator_type == "number":
415
+ op = num(N)
416
+ elif operator_type == "x":
417
+ # Position operator: x = (a + a†) / sqrt(2)
418
+ a = destroy(N)
419
+ op = (a + a.dag()) / np.sqrt(2)
420
+ elif operator_type == "p":
421
+ # Momentum operator: p = i(a† - a) / sqrt(2)
422
+ a = destroy(N)
423
+ op = 1j * (a.dag() - a) / np.sqrt(2)
424
+ else:
425
+ return {"success": False, "error": "Invalid operator type. Use 'number', 'x', or 'p'."}
426
+
427
+ exp_val = expect(op, state)
428
+ return {
429
+ "success": True,
430
+ "state": f"|{state_n}>",
431
+ "operator": operator_type,
432
+ "expectation_value": complex(exp_val).real if np.isreal(exp_val) else str(exp_val)
433
+ }
434
+ except Exception as e:
435
+ return {"success": False, "error": str(e)}
436
+
437
+
438
+ @mcp.tool(name="calculate_photon_statistics", description="Calculate photon number statistics for a quantum state.")
439
+ def calculate_photon_statistics(N: int, state_type: str, param: float) -> dict:
440
+ """
441
+ Calculates photon number statistics (mean, variance, Fano factor) for a quantum state.
442
+
443
+ Parameters:
444
+ - N (int): Hilbert space dimension.
445
+ - state_type (str): Type of state - "fock", "coherent", or "thermal".
446
+ - param (float): State parameter (n for Fock, |alpha| for coherent, n_avg for thermal).
447
+
448
+ Returns:
449
+ - dict: Contains photon statistics or error message.
450
+ """
451
+ try:
452
+ if state_type == "fock":
453
+ state = basis(N, int(param))
454
+ elif state_type == "coherent":
455
+ state = coherent(N, param)
456
+ elif state_type == "thermal":
457
+ state = thermal_dm(N, param)
458
+ else:
459
+ return {"success": False, "error": "Invalid state type. Use 'fock', 'coherent', or 'thermal'."}
460
+
461
+ n_op = num(N)
462
+ mean_n = float(expect(n_op, state).real)
463
+ var_n = float(variance(n_op, state).real)
464
+ fano_factor = var_n / mean_n if mean_n > 0 else 0
465
+
466
+ return {
467
+ "success": True,
468
+ "state_type": state_type,
469
+ "mean_photon_number": mean_n,
470
+ "variance": var_n,
471
+ "fano_factor": fano_factor,
472
+ "statistics_type": "sub-Poissonian" if fano_factor < 1 else ("Poissonian" if abs(fano_factor - 1) < 0.01 else "super-Poissonian")
473
+ }
474
+ except Exception as e:
475
+ return {"success": False, "error": str(e)}
476
+
477
+
478
+ # ==================== Metrics ====================
479
+
480
+ @mcp.tool(name="calculate_fidelity", description="Calculate the fidelity between two quantum states.")
481
+ def calculate_fidelity(N: int, state1_n: int, state2_n: int) -> dict:
482
+ """
483
+ Calculates the fidelity F between two Fock states.
484
+
485
+ Parameters:
486
+ - N (int): Hilbert space dimension.
487
+ - state1_n (int): First Fock state index.
488
+ - state2_n (int): Second Fock state index.
489
+
490
+ Returns:
491
+ - dict: Contains the fidelity value or error message.
492
+ """
493
+ try:
494
+ state1 = basis(N, state1_n)
495
+ state2 = basis(N, state2_n)
496
+ fid = fidelity(state1, state2)
497
+ return {
498
+ "success": True,
499
+ "state1": f"|{state1_n}>",
500
+ "state2": f"|{state2_n}>",
501
+ "fidelity": float(fid)
502
+ }
503
+ except Exception as e:
504
+ return {"success": False, "error": str(e)}
505
+
506
+
507
+ @mcp.tool(name="calculate_trace_distance", description="Calculate the trace distance between two quantum states.")
508
+ def calculate_trace_distance(N: int, state1_n: int, state2_n: int) -> dict:
509
+ """
510
+ Calculates the trace distance D between two Fock states.
511
+
512
+ Parameters:
513
+ - N (int): Hilbert space dimension.
514
+ - state1_n (int): First Fock state index.
515
+ - state2_n (int): Second Fock state index.
516
+
517
+ Returns:
518
+ - dict: Contains the trace distance value or error message.
519
+ """
520
+ try:
521
+ state1 = fock_dm(N, state1_n)
522
+ state2 = fock_dm(N, state2_n)
523
+ dist = tracedist(state1, state2)
524
+ return {
525
+ "success": True,
526
+ "state1": f"|{state1_n}><{state1_n}|",
527
+ "state2": f"|{state2_n}><{state2_n}|",
528
+ "trace_distance": float(dist)
529
+ }
530
+ except Exception as e:
531
+ return {"success": False, "error": str(e)}
532
+
533
+
534
+ # ==================== Entropy ====================
535
+
536
+ @mcp.tool(name="calculate_von_neumann_entropy", description="Calculate the von Neumann entropy of a density matrix.")
537
+ def calculate_von_neumann_entropy(N: int, n_thermal: float) -> dict:
538
+ """
539
+ Calculates the von Neumann entropy S = -Tr(rho * log(rho)) for a thermal state.
540
+
541
+ Parameters:
542
+ - N (int): Hilbert space dimension.
543
+ - n_thermal (float): Average thermal photon number.
544
+
545
+ Returns:
546
+ - dict: Contains the entropy value or error message.
547
+ """
548
+ try:
549
+ rho = thermal_dm(N, n_thermal)
550
+ entropy = entropy_vn(rho)
551
+ entropy_bits = entropy_vn(rho, base=2)
552
+ return {
553
+ "success": True,
554
+ "n_thermal": n_thermal,
555
+ "entropy_nats": float(entropy),
556
+ "entropy_bits": float(entropy_bits),
557
+ "purity": float((rho * rho).tr().real)
558
+ }
559
+ except Exception as e:
560
+ return {"success": False, "error": str(e)}
561
+
562
+
563
+ @mcp.tool(name="calculate_linear_entropy", description="Calculate the linear entropy of a quantum state.")
564
+ def calculate_linear_entropy(N: int, n_thermal: float) -> dict:
565
+ """
566
+ Calculates the linear entropy S_L = 1 - Tr(rho^2) for a thermal state.
567
+
568
+ Parameters:
569
+ - N (int): Hilbert space dimension.
570
+ - n_thermal (float): Average thermal photon number.
571
+
572
+ Returns:
573
+ - dict: Contains the linear entropy value or error message.
574
+ """
575
+ try:
576
+ rho = thermal_dm(N, n_thermal)
577
+ lin_entropy = entropy_linear(rho)
578
+ return {
579
+ "success": True,
580
+ "n_thermal": n_thermal,
581
+ "linear_entropy": float(lin_entropy),
582
+ "purity": 1 - float(lin_entropy)
583
+ }
584
+ except Exception as e:
585
+ return {"success": False, "error": str(e)}
586
+
587
+
588
+ @mcp.tool(name="calculate_concurrence", description="Calculate the concurrence (entanglement measure) for a two-qubit state.")
589
+ def calculate_concurrence(bell_state_type: str = "00") -> dict:
590
+ """
591
+ Calculates the concurrence for a Bell state (two-qubit entanglement measure).
592
+
593
+ Parameters:
594
+ - bell_state_type (str): Type of Bell state - "00", "01", "10", or "11".
595
+
596
+ Returns:
597
+ - dict: Contains the concurrence value or error message.
598
+ """
599
+ try:
600
+ state = bell_state(bell_state_type)
601
+ conc = concurrence(state)
602
+ return {
603
+ "success": True,
604
+ "bell_state_type": bell_state_type,
605
+ "concurrence": float(conc),
606
+ "is_maximally_entangled": abs(conc - 1.0) < 1e-10
607
+ }
608
+ except Exception as e:
609
+ return {"success": False, "error": str(e)}
610
+
611
+
612
+ # ==================== Wigner Function ====================
613
+
614
+ @mcp.tool(name="calculate_wigner_function", description="Calculate the Wigner function at a point in phase space.")
615
+ def calculate_wigner_function(N: int, state_type: str, param: float, x: float, y: float) -> dict:
616
+ """
617
+ Calculates the Wigner quasi-probability distribution W(x,p) at a point.
618
+
619
+ Parameters:
620
+ - N (int): Hilbert space dimension.
621
+ - state_type (str): Type of state - "fock", "coherent", or "thermal".
622
+ - param (float): State parameter.
623
+ - x (float): Position coordinate.
624
+ - y (float): Momentum coordinate.
625
+
626
+ Returns:
627
+ - dict: Contains the Wigner function value or error message.
628
+ """
629
+ try:
630
+ if state_type == "fock":
631
+ state = fock_dm(N, int(param))
632
+ elif state_type == "coherent":
633
+ state = coherent_dm(N, param)
634
+ elif state_type == "thermal":
635
+ state = thermal_dm(N, param)
636
+ else:
637
+ return {"success": False, "error": "Invalid state type."}
638
+
639
+ xvec = np.array([x])
640
+ yvec = np.array([y])
641
+ W = wigner(state, xvec, yvec)
642
+
643
+ return {
644
+ "success": True,
645
+ "state_type": state_type,
646
+ "x": x,
647
+ "y": y,
648
+ "wigner_value": float(W[0, 0])
649
+ }
650
+ except Exception as e:
651
+ return {"success": False, "error": str(e)}
652
+
653
+
654
+ @mcp.tool(name="calculate_q_function", description="Calculate the Husimi Q function at a point in phase space.")
655
+ def calculate_q_function(N: int, state_type: str, param: float, x: float, y: float) -> dict:
656
+ """
657
+ Calculates the Husimi Q quasi-probability distribution Q(alpha) at a point.
658
+
659
+ Parameters:
660
+ - N (int): Hilbert space dimension.
661
+ - state_type (str): Type of state - "fock", "coherent", or "thermal".
662
+ - param (float): State parameter.
663
+ - x (float): Real part of alpha.
664
+ - y (float): Imaginary part of alpha.
665
+
666
+ Returns:
667
+ - dict: Contains the Q function value or error message.
668
+ """
669
+ try:
670
+ if state_type == "fock":
671
+ state = fock_dm(N, int(param))
672
+ elif state_type == "coherent":
673
+ state = coherent_dm(N, param)
674
+ elif state_type == "thermal":
675
+ state = thermal_dm(N, param)
676
+ else:
677
+ return {"success": False, "error": "Invalid state type."}
678
+
679
+ xvec = np.array([x])
680
+ yvec = np.array([y])
681
+ Q = qfunc(state, xvec, yvec)
682
+
683
+ return {
684
+ "success": True,
685
+ "state_type": state_type,
686
+ "x": x,
687
+ "y": y,
688
+ "q_value": float(Q[0, 0])
689
+ }
690
+ except Exception as e:
691
+ return {"success": False, "error": str(e)}
692
+
693
+
694
+ # ==================== Random States ====================
695
+
696
+ @mcp.tool(name="generate_random_ket", description="Generate a random pure state (ket).")
697
+ def generate_random_ket(N: int, seed: Optional[int] = None) -> dict:
698
+ """
699
+ Generates a random normalized ket vector.
700
+
701
+ Parameters:
702
+ - N (int): Hilbert space dimension.
703
+ - seed (int, optional): Random seed for reproducibility.
704
+
705
+ Returns:
706
+ - dict: Contains the random state information or error message.
707
+ """
708
+ try:
709
+ state = rand_ket(N, seed=seed)
710
+ return {
711
+ "success": True,
712
+ "dimension": N,
713
+ "state_type": state.type,
714
+ "norm": float(state.norm()),
715
+ "dims": str(state.dims)
716
+ }
717
+ except Exception as e:
718
+ return {"success": False, "error": str(e)}
719
+
720
+
721
+ @mcp.tool(name="generate_random_density_matrix", description="Generate a random density matrix.")
722
+ def generate_random_density_matrix(N: int, pure: bool = False, seed: Optional[int] = None) -> dict:
723
+ """
724
+ Generates a random density matrix.
725
+
726
+ Parameters:
727
+ - N (int): Hilbert space dimension.
728
+ - pure (bool): If True, generates a pure state density matrix.
729
+ - seed (int, optional): Random seed for reproducibility.
730
+
731
+ Returns:
732
+ - dict: Contains the random density matrix information or error message.
733
+ """
734
+ try:
735
+ rho = rand_dm(N, pure=pure, seed=seed)
736
+ purity = float((rho * rho).tr().real)
737
+ return {
738
+ "success": True,
739
+ "dimension": N,
740
+ "is_pure": pure,
741
+ "trace": float(rho.tr().real),
742
+ "purity": purity,
743
+ "von_neumann_entropy": float(entropy_vn(rho))
744
+ }
745
+ except Exception as e:
746
+ return {"success": False, "error": str(e)}
747
+
748
+
749
+ @mcp.tool(name="generate_random_unitary", description="Generate a random unitary operator.")
750
+ def generate_random_unitary(N: int, seed: Optional[int] = None) -> dict:
751
+ """
752
+ Generates a random unitary operator from the Haar measure.
753
+
754
+ Parameters:
755
+ - N (int): Hilbert space dimension.
756
+ - seed (int, optional): Random seed for reproducibility.
757
+
758
+ Returns:
759
+ - dict: Contains the random unitary information or error message.
760
+ """
761
+ try:
762
+ U = rand_unitary(N, seed=seed)
763
+ # Check unitarity: U†U = I
764
+ identity_check = (U.dag() * U - qeye(N)).norm()
765
+ return {
766
+ "success": True,
767
+ "dimension": N,
768
+ "is_unitary": identity_check < 1e-10,
769
+ "unitarity_error": float(identity_check)
770
+ }
771
+ except Exception as e:
772
+ return {"success": False, "error": str(e)}
773
+
774
+
775
+ # ==================== Tensor Products ====================
776
+
777
+ @mcp.tool(name="tensor_product_states", description="Create a tensor product of multiple Fock states.")
778
+ def tensor_product_states(dimensions: List[int], states: List[int]) -> dict:
779
+ """
780
+ Creates a tensor product of Fock states.
781
+
782
+ Parameters:
783
+ - dimensions (list): List of Hilbert space dimensions for each subsystem.
784
+ - states (list): List of Fock state indices for each subsystem.
785
+
786
+ Returns:
787
+ - dict: Contains the tensor product state information or error message.
788
+ """
789
+ try:
790
+ if len(dimensions) != len(states):
791
+ return {"success": False, "error": "dimensions and states must have the same length."}
792
+
793
+ kets = [basis(d, n) for d, n in zip(dimensions, states)]
794
+ product_state = tensor(kets)
795
+
796
+ return {
797
+ "success": True,
798
+ "subsystem_dims": dimensions,
799
+ "subsystem_states": states,
800
+ "total_dimension": int(np.prod(dimensions)),
801
+ "result_dims": str(product_state.dims),
802
+ "result_shape": str(product_state.shape)
803
+ }
804
+ except Exception as e:
805
+ return {"success": False, "error": str(e)}
806
+
807
+
808
+ # ==================== Visualization Tools ====================
809
 
810
  @mcp.tool(name="plot_wigner_tool", description="Plot the Wigner function of a quantum state.")
811
+ def plot_wigner_tool(N: int, state_type: str, param: float) -> dict:
812
  """
813
  Plots the Wigner function for a given quantum state.
814
 
815
  Parameters:
816
+ - N (int): Hilbert space dimension.
817
+ - state_type (str): Type of state - "fock", "coherent", or "thermal".
818
+ - param (float): State parameter.
819
 
820
  Returns:
821
  - dict: A dictionary containing the success status and result or error message.
822
  """
823
  try:
824
+ if state_type == "fock":
825
+ state = fock_dm(N, int(param))
826
+ elif state_type == "coherent":
827
+ state = coherent_dm(N, param)
828
+ elif state_type == "thermal":
829
+ state = thermal_dm(N, param)
830
+ else:
831
+ return {"success": False, "error": "Invalid state type."}
832
+
833
  plot_wigner(state)
834
  return {"success": True, "result": "Wigner plot generated successfully."}
835
  except Exception as e:
836
  return {"success": False, "error": str(e)}
837
 
838
+
839
  @mcp.tool(name="plot_fock_distribution_tool", description="Plot the Fock distribution of a quantum state.")
840
+ def plot_fock_distribution_tool(N: int, state_type: str, param: float) -> dict:
841
  """
842
  Plots the Fock distribution for a given quantum state.
843
 
844
  Parameters:
845
+ - N (int): Hilbert space dimension.
846
+ - state_type (str): Type of state - "fock", "coherent", or "thermal".
847
+ - param (float): State parameter.
848
 
849
  Returns:
850
  - dict: A dictionary containing the success status and result or error message.
851
  """
852
  try:
853
+ if state_type == "fock":
854
+ state = basis(N, int(param))
855
+ elif state_type == "coherent":
856
+ state = coherent(N, param)
857
+ elif state_type == "thermal":
858
+ state = thermal_dm(N, param)
859
+ else:
860
+ return {"success": False, "error": "Invalid state type."}
861
+
862
  plot_fock_distribution(state)
863
  return {"success": True, "result": "Fock distribution plot generated successfully."}
864
  except Exception as e:
865
  return {"success": False, "error": str(e)}
866
 
867
+
868
+ @mcp.tool(name="plot_hinton_diagram", description="Plot a Hinton diagram for a density matrix.")
869
+ def plot_hinton_diagram(N: int, n_thermal: float) -> dict:
870
+ """
871
+ Plots a Hinton diagram showing the magnitude of density matrix elements.
872
+
873
+ Parameters:
874
+ - N (int): Hilbert space dimension.
875
+ - n_thermal (float): Average thermal photon number.
876
+
877
+ Returns:
878
+ - dict: A dictionary containing the success status and result or error message.
879
+ """
880
+ try:
881
+ rho = thermal_dm(N, n_thermal)
882
+ hinton(rho)
883
+ return {"success": True, "result": "Hinton diagram generated successfully."}
884
+ except Exception as e:
885
+ return {"success": False, "error": str(e)}
886
+
887
+
888
+ @mcp.tool(name="plot_matrix_histogram", description="Plot a 3D histogram of a density matrix.")
889
+ def plot_matrix_histogram(N: int, state_type: str, param: float) -> dict:
890
+ """
891
+ Plots a 3D histogram of the density matrix elements.
892
+
893
+ Parameters:
894
+ - N (int): Hilbert space dimension.
895
+ - state_type (str): Type of state - "fock", "coherent", or "thermal".
896
+ - param (float): State parameter.
897
+
898
+ Returns:
899
+ - dict: A dictionary containing the success status and result or error message.
900
+ """
901
+ try:
902
+ if state_type == "fock":
903
+ rho = fock_dm(N, int(param))
904
+ elif state_type == "coherent":
905
+ rho = coherent_dm(N, param)
906
+ elif state_type == "thermal":
907
+ rho = thermal_dm(N, param)
908
+ else:
909
+ return {"success": False, "error": "Invalid state type."}
910
+
911
+ matrix_histogram(rho)
912
+ return {"success": True, "result": "Matrix histogram generated successfully."}
913
+ except Exception as e:
914
+ return {"success": False, "error": str(e)}
915
+
916
+
917
  def create_app() -> FastMCP:
918
  """
919
  Creates and returns the FastMCP instance for the service.