Skip to main contentIBM Quantum Documentation Preview
This is a preview build of IBM Quantum® documentation. Refer to quantum.cloud.ibm.com/docs for the official documentation.

How to use quimb.tensor.TNOptimizer directly

Quimb provides a mechanism for optimizing tensor networks through its TNOptimizer interface. The Quimb backend provided by this addon uses this under the hood. This how-to guide demonstrates how to work with this object directly, in case some users want more direct access to it.

Set up a model Hamiltonian

from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian

# Generate some coupling map to use for this example
coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)

# Choose a 10-qubit circle on this coupling map
reduced_coupling_map = coupling_map.reduce([0, 13, 1, 14, 10, 16, 4, 15, 3, 9])

# Get a qubit operator describing the Ising field model
hamiltonian = generate_xyz_hamiltonian(
    reduced_coupling_map,
    coupling_constants=(0.0, 0.0, 1.0),
    ext_magnetic_field=(0.4, 0.0, 0.0),
)

Output:

/tmp/ipykernel_3158/2599302630.py:1: DeprecationWarning: Using Qiskit with Python 3.9 is deprecated as of the 2.1.0 release. Support for running Qiskit with Python 3.9 will be removed in the 2.3.0 release, which coincides with when Python 3.9 goes end of life.
  from qiskit.transpiler import CouplingMap

Set up quimb simulator with default options

import quimb.tensor as qtn

from qiskit_addon_aqc_tensor.simulation.quimb import (
    QuimbSimulator,
    qiskit_ansatz_to_quimb,
    recover_parameters_from_quimb,
)

simulator = QuimbSimulator(qtn.Circuit)

Generate target circuit

from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit

from qiskit_addon_aqc_tensor.simulation import (
    compute_overlap,
    tensornetwork_from_circuit,
)

evolution_time = 0.4

target_circuit = generate_time_evolution_circuit(
    hamiltonian,
    synthesis=SuzukiTrotter(reps=8),
    time=evolution_time,
)

target_tns = tensornetwork_from_circuit(target_circuit, simulator)

Generate ansatz from a shallower circuit

from qiskit_addon_aqc_tensor.ansatz_generation import (
    AnsatzBlock,
    generate_ansatz_from_circuit,
)

initial_shallow_circuit = generate_time_evolution_circuit(
    hamiltonian,
    synthesis=SuzukiTrotter(reps=2),
    time=evolution_time,
)
ansatz, initial_parameters = generate_ansatz_from_circuit(initial_shallow_circuit)
ansatz = ansatz.decompose(AnsatzBlock)
ansatz.draw("mpl", fold=-1)

Output:

Output of the previous code cell

Initialize objective function

from qiskit_addon_aqc_tensor.objective import MaximizeStateFidelity

objective = MaximizeStateFidelity(target_tns, None, None)

Convert Qiskit ansatz and initial parameters to a Quimb parametrized circuit

circ, conversion_context = qiskit_ansatz_to_quimb(ansatz, initial_parameters)

Perform optimization of Quimb circuit using automatic differentiation

from qiskit_addon_aqc_tensor.simulation.quimb import tnoptimizer_objective_kwargs

tnopt = qtn.TNOptimizer(
    circ,
    **tnoptimizer_objective_kwargs(objective),
    autodiff_backend="jax",  # OPTIONS: jax, autograd, torch, etc.
)
circ_opt = tnopt.optimize(20)

Output:


  0%|          | 0/20 [00:00<?, ?it/s]

  5%|▌         | 1/20 [00:32<10:10, 32.14s/it]

+0.000196685651 [best: +0.000196685651] :   5%|▌         | 1/20 [00:32<10:10, 32.14s/it]

+0.788653314114 [best: +0.000196685651] :  10%|█         | 2/20 [00:32<09:38, 32.14s/it]

+0.000034331981 [best: +0.000034331981] :  15%|█▌        | 3/20 [00:32<09:06, 32.14s/it]

+0.000023126468 [best: +0.000023126468] :  20%|██        | 4/20 [00:32<08:34, 32.14s/it]

+0.000020861517 [best: +0.000020861517] :  25%|██▌       | 5/20 [00:32<08:02, 32.14s/it]

+0.000024676170 [best: +0.000020861517] :  30%|███       | 6/20 [00:32<07:29, 32.14s/it]

+0.000021695972 [best: +0.000020861517] :  35%|███▌      | 7/20 [00:32<06:57, 32.14s/it]

+0.000021219141 [best: +0.000020861517] :  40%|████      | 8/20 [00:32<06:25, 32.14s/it]

+0.000020861517 [best: +0.000020861517] :  45%|████▌     | 9/20 [00:32<05:53, 32.14s/it]

+0.000020861517 [best: +0.000020861517] :  50%|█████     | 10/20 [00:32<05:21, 32.14s/it]

+0.000020861517 [best: +0.000020861517] :  55%|█████▌    | 11/20 [00:32<04:49, 32.14s/it]

+0.000020861517 [best: +0.000020861517] :  60%|██████    | 12/20 [00:32<04:17, 32.14s/it]

+0.000020861517 [best: +0.000020861517] :  65%|██████▌   | 13/20 [00:32<00:12,  1.78s/it]

+0.000020861517 [best: +0.000020861517] :  65%|██████▌   | 13/20 [00:32<00:12,  1.78s/it]

+0.000020861517 [best: +0.000020861517] :  70%|███████   | 14/20 [00:32<00:10,  1.78s/it]

+0.000020861517 [best: +0.000020861517] :  75%|███████▌  | 15/20 [00:32<00:08,  1.78s/it]

+0.000020861517 [best: +0.000020861517] :  80%|████████  | 16/20 [00:32<00:07,  1.78s/it]

+0.000020861517 [best: +0.000020861517] :  85%|████████▌ | 17/20 [00:32<00:05,  1.78s/it]

+0.000020861517 [best: +0.000020861517] :  90%|█████████ | 18/20 [00:32<00:03,  1.78s/it]

+0.000020861517 [best: +0.000020861517] :  95%|█████████▌| 19/20 [00:32<00:01,  1.78s/it]

+0.000020861517 [best: +0.000020861517] : 100%|██████████| 20/20 [00:32<00:00,  1.78s/it]

+0.000020861517 [best: +0.000020861517] : : 21it [00:32,  1.78s/it]                      

+0.000020861517 [best: +0.000020861517] : : 22it [00:32,  1.78s/it]

+0.000020861517 [best: +0.000020861517] : : 22it [00:32,  1.47s/it]

Recover final parameters from the quimb circuit

final_parameters = recover_parameters_from_quimb(circ_opt, conversion_context)

Check fidelity of final, compressed state w/ respect to target state

compressed_circuit = ansatz.assign_parameters(final_parameters)
compressed_state = tensornetwork_from_circuit(compressed_circuit, simulator)
abs(compute_overlap(target_tns, compressed_state)) ** 2

Output:

0.9999992039939346

Compare with fidelity of initial shallow state w/ respect to target state

initial_shallow_state = tensornetwork_from_circuit(initial_shallow_circuit, simulator)
abs(compute_overlap(target_tns, initial_shallow_state)) ** 2

Output:

0.9998389457702321