@@ -20,6 +20,16 @@ def adaptive_vmap(
2020 static_argnums : Optional [Union [int , Sequence [int ]]] = None ,
2121 chunk_size : Optional [int ] = None ,
2222) -> Callable [..., Any ]:
23+ """
24+ Vectorized map with adaptive chunking for memory efficiency.
25+
26+ :param f: Function to be vectorized
27+ :param vectorized_argnums: Arguments to be vectorized over
28+ :param static_argnums: Arguments that remain static during vectorization
29+ :param chunk_size: Size of chunks for batch processing, None means no chunking
30+ (naive vmap)
31+ :return: Vectorized function
32+ """
2333 if chunk_size is None :
2434 return backend .vmap (f , vectorized_argnums ) # type: ignore
2535
@@ -94,6 +104,29 @@ def qng(
94104 postprocess : Optional [str ] = "qng" ,
95105 mode : str = "fwd" ,
96106) -> Callable [..., Tensor ]:
107+ """
108+ Compute quantum natural gradient for quantum circuit optimization.
109+
110+ :param f: Function that takes parameters and returns quantum state
111+ :param kernel: Type of kernel to use ("qng" or "dynamics"), the former has the second term
112+ :param postprocess: Post-processing method ("qng" or None)
113+ :param mode: Mode of differentiation ("fwd" or "rev")
114+ :return: Function computing QNG matrix
115+
116+ :Example:
117+
118+ >>> import tensorcircuit as tc
119+ >>> def ansatz(params):
120+ ... c = tc.Circuit(2)
121+ ... c.rx(0, theta=params[0])
122+ ... c.ry(1, theta=params[1])
123+ ... return c.state()
124+ >>> qng_fn = tc.experimental.qng(ansatz)
125+ >>> params = tc.array_to_tensor([0.5, 0.8])
126+ >>> qng_matrix = qng_fn(params)
127+ >>> print(qng_matrix.shape) # (2, 2)
128+ """
129+
97130 # for both qng and qng2 calculation, we highly recommended complex-dtype but real valued inputs
98131 def wrapper (params : Tensor , ** kws : Any ) -> Tensor :
99132 params = backend .cast (params , dtype = dtypestr ) # R->C protection
@@ -406,19 +439,46 @@ def hamiltonian_evol(
406439 callback : Optional [Callable [..., Any ]] = None ,
407440) -> Tensor :
408441 """
409- Fast implementation of static full Hamiltonian evolution
410- ( default as imaginary time)
442+ Fast implementation of time independent Hamiltonian evolution using eigendecomposition.
443+ By default, performs imaginary time evolution.
411444
412- :param tlist: _description_
445+ :param tlist: Time points for evolution
413446 :type tlist: Tensor
414- :param h: _description_
447+ :param h: Time-independent Hamiltonian matrix
415448 :type h: Tensor
416- :param psi0: _description_
449+ :param psi0: Initial state vector
417450 :type psi0: Tensor
418- :param callback: _description_, defaults to None
451+ :param callback: Optional function to process state at each time point
419452 :type callback: Optional[Callable[..., Any]], optional
420- :return: Tensor
421- :rtype: result dynamics on ``tlist``
453+ :return: Evolution results at each time point. If callback is None, returns state vectors;
454+ otherwise returns callback results
455+ :rtype: Tensor
456+
457+ :Example:
458+
459+ >>> import tensorcircuit as tc
460+ >>> import numpy as np
461+ >>> # Define a simple 2-qubit Hamiltonian
462+ >>> h = tc.array_to_tensor([
463+ ... [1.0, 0.0, 0.0, 0.0],
464+ ... [0.0, -1.0, 2.0, 0.0],
465+ ... [0.0, 2.0, -1.0, 0.0],
466+ ... [0.0, 0.0, 0.0, 1.0]
467+ ... ])
468+ >>> # Initial state |00⟩
469+ >>> psi0 = tc.array_to_tensor([1.0, 0.0, 0.0, 0.0])
470+ >>> # Evolution times
471+ >>> times = tc.array_to_tensor([0.0, 0.5, 1.0])
472+ >>> # Evolve and get states
473+ >>> states = tc.experimental.hamiltonian_evol(times, h, psi0)
474+ >>> print(states.shape) # (3, 4)
475+
476+
477+ Note:
478+ 1. The Hamiltonian must be time-independent
479+ 2. For time-dependent Hamiltonians, use ``evol_local`` or ``evol_global`` instead
480+ 3. The evolution is performed in imaginary time by default (factor -t in exponential)
481+ 4. The state is automatically normalized at each time point
422482 """
423483 es , u = backend .eigh (h )
424484 utpsi0 = backend .reshape (
0 commit comments