Skip to content

Commit 783216b

Browse files
update the circuit initialization logic for analogcircuit
1 parent ca1f7fa commit 783216b

File tree

2 files changed

+40
-15
lines changed

2 files changed

+40
-15
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727

2828
TensorCircuit-NG is the next-generation open-source high-performance quantum software framework, built upon tensornetwork engines, supporting for automatic differentiation, just-in-time compiling, hardware acceleration, vectorized parallelism and distributed training, providing unified infrastructures and interfaces for quantum programming. It can compose quantum circuits, neural networks and tensor networks seamlessly with high simulation efficiency and flexibility.
2929

30-
TensorCircuit-NG is built on top of modern machine learning frameworks: Jax, TensorFlow, and PyTorch. It is specifically suitable for large-scale simulations of quantum-classical hybrid paradigm and variational quantum algorithms in ideal, noisy, Clifford, qudit, approximate, analog, and fermionic cases. It also supports quantum hardware access and provides CPU/GPU/QPU hybrid deployment solutions.
30+
TensorCircuit-NG is built on top of modern machine learning frameworks: Jax, TensorFlow, and PyTorch. It is specifically suitable for large-scale simulations of quantum-classical hybrid paradigm and variational quantum algorithms in ideal (`Circuit`), noisy (`DMCircuit`), Clifford (`StabilizerCircuit`), qudit (`QuditCircuit`), approximate (`MPSCircuit`), analog (`AnalogCircuit`), and fermionic (`FGSCircuit`) cases. It also supports quantum hardware access and provides CPU/GPU/QPU hybrid deployment solutions.
3131

32-
TensorCircuit-NG is the actively maintained official version and a [fully compatible](https://tensorcircuit-ng.readthedocs.io/en/latest/faq.html#what-is-the-relation-between-tensorcircuit-and-tensorcircuit-ng) successor to TensorCircuit with more new features (stabilizer circuit, multi-card distributed simulation, etc.) and bug fixes (support latest `numpy>2` and `qiskit>1`).
32+
TensorCircuit-NG is the only actively maintained official version and a [fully compatible](https://tensorcircuit-ng.readthedocs.io/en/latest/faq.html#what-is-the-relation-between-tensorcircuit-and-tensorcircuit-ng) successor to TensorCircuit with more new features (stabilizer circuit, qudit circuit, analog circuit, multi-GPU distributed simulation, etc.) and bug fixes (support latest `numpy>2` and `qiskit>1`).
3333

3434
## Getting Started
3535

tensorcircuit/analogcircuit.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""
22
Analog-Digital Hybrid Circuit class wrapper
3+
only support jax backend
34
"""
45

56
from typing import Any, List, Optional, Callable, Dict, Tuple, Union, Sequence
@@ -21,7 +22,9 @@
2122

2223
@dataclass
2324
class AnalogBlock:
24-
"""A data structure to hold information about an analog evolution block."""
25+
"""
26+
A data structure to hold information about an analog evolution block.
27+
"""
2528

2629
hamiltonian_func: Callable[[Tensor], Tensor]
2730
time: float
@@ -45,7 +48,18 @@ def __init__(
4548
"""
4649
Initializes the hybrid circuit.
4750
48-
:param num_qubits: The number of qubits in the circuit.
51+
:param nqubits: The number of qubits in the circuit.
52+
:type nqubits: int
53+
:param dim: The local Hilbert space dimension per site. Qudit is supported for 2 <= d <= 36.
54+
:type dim: If None, the dimension of the circuit will be `2`, which is a qubit system.
55+
:param inputs: If not None, the initial state of the circuit is taken as ``inputs``
56+
instead of :math:`\vert 0 \rangle^n` qubits, defaults to None.
57+
:type inputs: Optional[Tensor], optional
58+
:param mps_inputs: QuVector for a MPS like initial wavefunction.
59+
:type mps_inputs: Optional[QuOperator]
60+
:param split: dict if two qubit gate is ready for split, including parameters for at least one of
61+
``max_singular_values`` and ``max_truncation_err``.
62+
:type split: Optional[Dict[str, Any]]
4963
"""
5064
self.num_qubits, self._nqubits = nqubits, nqubits
5165
self.dim = 2**self.num_qubits
@@ -57,7 +71,7 @@ def __init__(
5771

5872
# List of digital circuits, starting with one empty circuit.
5973
self.digital_circuits: List[Circuit] = [
60-
Circuit(self.num_qubits, self.inputs, mps_inputs, split, dim)
74+
Circuit(self.num_qubits, inputs, mps_inputs, split, dim)
6175
]
6276

6377
# List of analog blocks, each containing the Hamiltonian function, time, and solver options.
@@ -66,18 +80,25 @@ def __init__(
6680
self._solver_options: Dict[str, Any] = {}
6781

6882
def set_solver_options(self, **kws: Any) -> None:
83+
"""
84+
set solver options globally for this circuit object
85+
"""
6986
self._solver_options = kws
7087

7188
@property
7289
def effective_circuit(self) -> Circuit:
73-
"""Returns the effective circuit after all blocks have been added."""
90+
"""
91+
Returns the effective circuit after all blocks have been added.
92+
"""
7493
if self._effective_circuit is None:
7594
self.state()
7695
return self._effective_circuit # type: ignore
7796

7897
@property
7998
def current_digital_circuit(self) -> Circuit:
80-
"""Returns the last (currently active) digital circuit."""
99+
"""
100+
Returns the last (currently active) digital circuit.
101+
"""
81102
return self.digital_circuits[-1]
82103

83104
def add_analog_block(
@@ -94,11 +115,14 @@ def add_analog_block(
94115
95116
:param hamiltonian_func: A function H(t) that takes a time `t` (from 0 to `time`)
96117
and returns the Hamiltonian matrix at that instant.
118+
:type hamiltonian_func: Callable[[float], np.ndarray]
97119
:param time: The total evolution time 'T'.
120+
:type time: float
98121
:param index: The indices of the qubits to apply the analog evolution to. Defaults None for
99122
global application.
100-
:param solver_options: Keyword arguments passed directly to `scipy.integrate.solve_ivp`.
101-
(e.g., method='RK45', rtol=1e-6, atol=1e-8)
123+
:type index: Optional[List[int]]
124+
:param solver_options: Keyword arguments passed directly to `tc.timeevol.ode_evolve`
125+
:type solver_options: Dict[str, Any]
102126
"""
103127
# Create and store the analog block information
104128
time = backend.convert_to_tensor(time, dtype=rdtypestr)
@@ -152,14 +176,12 @@ def state(self) -> Tensor:
152176
:return: The final state vector after the full evolution
153177
:rtype: Tensor
154178
"""
155-
psi = self.inputs
156-
157179
# Propagate the state through the alternating circuit blocks
158180
for i, analog_block in enumerate(self.analog_blocks):
159181
# 1. Apply Digital Block i
160182
digital_c = self.digital_circuits[i]
161183
if i > 0:
162-
digital_c.replace_inputs(psi)
184+
digital_c.replace_inputs(psi) # type: ignore
163185
psi = digital_c.wavefunction()
164186

165187
if analog_block.index is None:
@@ -181,8 +203,11 @@ def state(self) -> Tensor:
181203
# TODO(@refraction-ray): support more time evol methods
182204

183205
# 3. Apply the final digital circuit
184-
self.digital_circuits[-1].replace_inputs(psi)
185-
psi = self.digital_circuits[-1].wavefunction()
206+
if self.analog_blocks:
207+
self.digital_circuits[-1].replace_inputs(psi)
208+
psi = self.digital_circuits[-1].wavefunction()
209+
else:
210+
psi = self.digital_circuits[-1].wavefunction()
186211
self._effective_circuit = Circuit(self.num_qubits, inputs=psi)
187212

188213
return psi
@@ -382,7 +407,7 @@ def __repr__(self) -> str:
382407
if i < len(self.analog_blocks):
383408
block = self.analog_blocks[i]
384409
s += f"--- Analog Block {i} (T={block.time}) ---\n"
385-
s += f" H(t) function: '{block.hamiltonian_func.__name__}'\n"
410+
s += f" H(t) function: '{block.hamiltonian_func.__name__}'\n"
386411

387412
s += "=" * 40
388413
return s

0 commit comments

Comments
 (0)