期望值计算支持;更新后端调用
Some checks failed
Build wheels / build (ubuntu-latest, 3.11) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.12) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / check (push) Has been cancelled
Tests / build (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.13) (push) Has been cancelled
Some checks failed
Build wheels / build (ubuntu-latest, 3.11) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.12) (push) Has been cancelled
Build wheels / build (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / check (push) Has been cancelled
Tests / build (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / build (ubuntu-latest, 3.13) (push) Has been cancelled
This commit is contained in:
@@ -352,6 +352,149 @@ def _string_to_quimb_operator(self, op_str):
|
||||
return op
|
||||
|
||||
|
||||
def expectation(self, circuit, observable, parallel=None, parallel_opts=None):
|
||||
"""
|
||||
Compute expectation value with optional parallel acceleration.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
circuit : qibo.models.Circuit
|
||||
The quantum circuit.
|
||||
observable : qibo.hamiltonians.SymbolicHamiltonian or form
|
||||
The observable to measure.
|
||||
parallel : str, optional
|
||||
Parallelization method: 'mpi', 'processpool', or None (default).
|
||||
parallel_opts : dict, optional
|
||||
Options for parallel execution:
|
||||
- max_repeats: int (default 1024)
|
||||
- max_time: int (default 300)
|
||||
- search_workers: int (default 48, processpool only)
|
||||
- mpi_contract: bool (default False, use MPI for contraction)
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The expectation value.
|
||||
"""
|
||||
from qibotn.observables import check_observable, extract_gates_and_qubits
|
||||
|
||||
if parallel_opts is None:
|
||||
parallel_opts = {}
|
||||
|
||||
observable = check_observable(observable, circuit.nqubits)
|
||||
|
||||
if parallel is None:
|
||||
# Use original implementation
|
||||
from qibotn.observables import extract_gates_and_qubits
|
||||
all_terms = extract_gates_and_qubits(observable)
|
||||
|
||||
qc = self._qibo_circuit_to_quimb(
|
||||
circuit,
|
||||
quimb_circuit_type=self.circuit_ansatz,
|
||||
gate_opts={"max_bond": self.max_bond_dimension, "cutoff": self.svd_cutoff},
|
||||
)
|
||||
|
||||
exp_val = 0.0
|
||||
for coeff, factors in all_terms:
|
||||
op = None
|
||||
where = []
|
||||
for qubit, gate_name in factors:
|
||||
p = qu.pauli(gate_name.lower())
|
||||
op = p if op is None else op & p
|
||||
where.append(qubit)
|
||||
|
||||
val = qc.local_expectation(
|
||||
op, tuple(where),
|
||||
backend=self.backend,
|
||||
optimize=self.contractions_optimizer,
|
||||
simplify_sequence="ADCRS",
|
||||
simplify_atol=1e-12,
|
||||
)
|
||||
exp_val += coeff * val
|
||||
|
||||
return self.real(exp_val)
|
||||
|
||||
else:
|
||||
# Use parallel implementation
|
||||
return self._expectation_parallel(circuit, observable, parallel, parallel_opts)
|
||||
|
||||
|
||||
def _expectation_parallel(self, circuit, observable, method, opts):
|
||||
"""Parallel expectation value computation."""
|
||||
from qibotn.observables import extract_gates_and_qubits
|
||||
from qibotn.parallel import parallel_path_search, parallel_contract
|
||||
import torch
|
||||
|
||||
try:
|
||||
from mpi4py import MPI
|
||||
comm = MPI.COMM_WORLD if method == 'mpi' else None
|
||||
rank = comm.Get_rank() if comm else 0
|
||||
size = comm.Get_size() if comm else 1
|
||||
except ImportError:
|
||||
comm, rank, size = None, 0, 1
|
||||
|
||||
max_repeats = opts.get('max_repeats', 1024)
|
||||
max_time = opts.get('max_time', 300)
|
||||
search_workers = opts.get('search_workers', 48)
|
||||
mpi_contract = opts.get('mpi_contract', False)
|
||||
torch_threads = opts.get('torch_threads', None)
|
||||
|
||||
qc = self._qibo_circuit_to_quimb(
|
||||
circuit,
|
||||
quimb_circuit_type=self.circuit_ansatz,
|
||||
gate_opts={"max_bond": self.max_bond_dimension, "cutoff": self.svd_cutoff},
|
||||
)
|
||||
|
||||
all_terms = extract_gates_and_qubits(observable)
|
||||
my_terms = all_terms[rank::size]
|
||||
|
||||
if method == 'mpi' and comm:
|
||||
torch.set_num_threads(max(1, 96 // size))
|
||||
elif torch_threads:
|
||||
torch.set_num_threads(torch_threads)
|
||||
|
||||
my_exp = 0.0
|
||||
for coeff, factors in my_terms:
|
||||
op = None
|
||||
where = []
|
||||
for qubit, gate_name in factors:
|
||||
p = qu.pauli(gate_name.lower())
|
||||
op = p if op is None else op & p
|
||||
where.append(qubit)
|
||||
|
||||
tn = qc.local_expectation(op, tuple(where), rehearse='tn')
|
||||
|
||||
tree = parallel_path_search(
|
||||
tn, tn.outer_inds(),
|
||||
method=method,
|
||||
total_repeats=max_repeats,
|
||||
max_time=max_time,
|
||||
n_workers=search_workers
|
||||
)
|
||||
|
||||
if tree is None:
|
||||
continue
|
||||
|
||||
if mpi_contract and comm and size > 1:
|
||||
arrays = [self.engine.asarray(a) for a in tn.arrays]
|
||||
val = parallel_contract(tree, arrays, method='mpi', comm=comm)
|
||||
else:
|
||||
for tensor in tn.tensors:
|
||||
tensor._data = torch.from_numpy(self.engine.asarray(tensor._data)).to(torch.complex128)
|
||||
val = complex(tn.contract(all, output_inds=(), optimize=tree))
|
||||
|
||||
my_exp += coeff * complex(val)
|
||||
|
||||
if comm:
|
||||
all_exp = comm.gather(my_exp, root=0)
|
||||
if rank == 0:
|
||||
total_exp = sum(all_exp)
|
||||
return self.real(total_exp)
|
||||
return 0.0
|
||||
|
||||
return self.real(my_exp)
|
||||
|
||||
|
||||
CLASSES_ROOTS = {"numpy": "Numpy", "torch": "PyTorch", "jax": "Jax"}
|
||||
|
||||
METHODS = {
|
||||
@@ -362,6 +505,8 @@ METHODS = {
|
||||
"exp_value_observable_symbolic": exp_value_observable_symbolic,
|
||||
"_qibo_circuit_to_quimb": _qibo_circuit_to_quimb,
|
||||
"_string_to_quimb_operator": _string_to_quimb_operator,
|
||||
"expectation": expectation,
|
||||
"_expectation_parallel": _expectation_parallel,
|
||||
"circuit_ansatz": circuit_ansatz,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user