Skip to main content
IBM Quantum Platform

Creare un modello di funzione Qiskit per la simulazione hamiltoniana

Questo modello racchiude un flusso di lavoro per simulare l'evoluzione temporale di uno stato iniziale rispetto a un hamiltoniano basato sullo spin definito dall'utente e restituisce una serie di valori attesi specificati utilizzando l'add-on AQC-Tensor Qiskit.

Questo modello è strutturato come un modello Qiskit con i seguenti passaggi:

1. Raccolta di input e mappatura del problema

Questa sezione prende in input l'hamiltoniana da simulare, uno stato iniziale sotto forma di QuantumCircuit, un insieme di osservabili per stimare i valori di aspettativa e una specifica di opzioni per l'addon AQC. Questa fase convalida la presenza di tutti i dati di input richiesti e il loro formato corretto.

Gli argomenti in ingresso vengono quindi utilizzati per costruire i circuiti quantistici e gli operatori rilevanti per il flusso di lavoro. Si crea un circuito di destinazione e si trova una rappresentazione di stato del prodotto matriciale di questo circuito utilizzando l'addon AQC. In seguito, viene generato un circuito di ansatz e ottimizzato con metodi di rete tensoriale, producendo un circuito finale che esegue il resto dell'evoluzione temporale.

2. Preparare i circuiti generati per l'esecuzione

I circuiti generati dall'addon AQC vengono poi transpilati per essere eseguiti su un backend scelto. Viene creata un'istanza EstimatorV2 viene creata con un insieme predefinito di opzioni di attenuazione degli errori per gestire l'esecuzione del circuito.

3. Esecuzione

Infine, il circuito di ansatz viene transpilato ed eseguito su una QPU e raccoglie le stime per tutti i valori di aspettativa specificati, che vengono restituiti in un formato serializzabile per l'accesso da parte dell'utente.


Scrivi il modello di funzione

In primo luogo, scrivere un modello di funzione per la simulazione hamiltoniana che utilizzi l 'add-on AQC-Tensor Qiskit per mappare la descrizione del problema su un circuito a profondità ridotta per l'esecuzione su hardware.

Se scarichi questa pagina e la visualizzi in locale in un editor di file di testo, noterai che alcune delle celle di codice contengono il comando magico %%writefile. Questo comando magico salva il codice in ./source_files/template_hamiltonian_simulation.py, ovvero il modello di funzione che puoi caricare su ed eseguire in remoto tramite Qiskit Serverless.

Raccogliere e convalidare gli input

Iniziate con l'ottenere gli input per il modello. Questo esempio ha input specifici del dominio rilevanti per la simulazione hamiltoniana (come l'hamiltoniano e l'osservabile) e opzioni specifiche della capacità (come la quantità di compressione degli strati iniziali del circuito di Trotter usando AQC-Tensor, o opzioni avanzate per la regolazione fine della soppressione e della mitigazione degli errori al di là dei valori predefiniti che fanno parte di questo esempio).

./source_files/template_hamiltonian_simulation.py
from qiskit import QuantumCircuit
from qiskit_serverless import get_arguments, save_result


# Extract parameters from arguments
#
# Do this at the top of the program so it fails early if any required arguments
# are missing or invalid.

arguments = get_arguments()

dry_run = arguments.get("dry_run", False)
backend_name = arguments["backend_name"]

aqc_evolution_time = arguments["aqc_evolution_time"]
aqc_ansatz_num_trotter_steps = arguments["aqc_ansatz_num_trotter_steps"]
aqc_target_num_trotter_steps = arguments["aqc_target_num_trotter_steps"]

remainder_evolution_time = arguments["remainder_evolution_time"]
remainder_num_trotter_steps = arguments["remainder_num_trotter_steps"]

# Stop if this fidelity is achieved
aqc_stopping_fidelity = arguments.get("aqc_stopping_fidelity", 1.0)
# Stop after this number of iterations, even if stopping fidelity is not achieved
aqc_max_iterations = arguments.get("aqc_max_iterations", 500)

hamiltonian = arguments["hamiltonian"]
observable = arguments["observable"]
initial_state = arguments.get("initial_state",
    QuantumCircuit(hamiltonian.num_qubits))
./source_files/template_hamiltonian_simulation.py (appended)
import numpy as np
import json
from mergedeep import merge


# Configure `EstimatorOptions`, to control the parameters
# of the hardware experiment
#
# Set default options
estimator_default_options = {
    "resilience": {
        "measure_mitigation": True,
        "zne_mitigation": True,
        "zne": {
            "amplifier": "gate_folding",
            "noise_factors": [1, 2, 3],
            "extrapolated_noise_factors": list(np.linspace(0, 3, 31)),
            "extrapolator": ["exponential", "linear", "fallback"],
        },
        "measure_noise_learning": {
            "num_randomizations": 512,
            "shots_per_randomization": 512,
        },
    },
    "twirling": {
        "enable_gates": True,
        "enable_measure": True,
        "num_randomizations": 300,
        "shots_per_randomization": 100,
        "strategy": "active",
    },
}
# Merge with user-provided options
estimator_options = merge(
    arguments.get("estimator_options", {}), estimator_default_options
)

Quando il modello di funzione è in esecuzione, è utile riportare le informazioni nei log utilizzando le istruzioni di stampa, in modo da poter valutare meglio l'andamento del carico di lavoro. Di seguito è riportato un semplice esempio di stampa del sito estimator_options , in modo da avere una registrazione delle opzioni dell'Estimatore effettivamente utilizzate. Ci sono molti altri esempi simili in tutto il programma per segnalare i progressi durante l'esecuzione, tra cui il valore della funzione obiettivo durante la componente iterativa di AQC-Tensor e la profondità di due qubit del circuito finale dell'instruction set architecture (ISA) destinato all'esecuzione su hardware.

./source_files/template_hamiltonian_simulation.py (appended)
print("estimator_options =", json.dumps(estimator_options, indent=4))

Convalida gli input

Un aspetto importante per garantire che il modello possa essere riutilizzato per una serie di input è la convalida dell'input. Il codice seguente è un esempio di verifica che la fedeltà di arresto durante AQC-Tensor sia stata specificata in modo appropriato e, in caso contrario, restituisce un messaggio di errore informativo su come risolvere l'errore.

./source_files/template_hamiltonian_simulation.py (appended)
# Perform parameter validation

if not 0.0 < aqc_stopping_fidelity <= 1.0:
    raise ValueError(
        f"Invalid stopping fidelity: {aqc_stopping_fidelity}.  "
        f"It must be a positive float no greater than 1."
    )

Preparare gli output della funzione

Per prima cosa, preparare un dizionario che contenga tutti gli output dei modelli di funzione. Le chiavi verranno aggiunte a questo dizionario nel corso del flusso di lavoro e verrà restituito alla fine del programma.

./source_files/template_hamiltonian_simulation.py (appended)
output = {}

Mappare il problema ed eseguire la pre-elaborazione del circuito con AQC

L'ottimizzazione di AQC-Tensor avviene nel passo 1 di un modello Qiskit. In primo luogo, viene costruito uno stato di destinazione. In questo esempio, è costruito a partire da un circuito target che evolve la stessa hamiltoniana per lo stesso periodo di tempo della parte AQC. Quindi, si genera un'ansatz da un circuito equivalente, ma con meno passi di Trotter. Nella parte principale dell'algoritmo AQC, tale ansatz viene avvicinato iterativamente allo stato target. Infine, il risultato viene combinato con il resto dei passi di Trotter necessari per raggiungere il tempo di evoluzione desiderato.

Si notino gli esempi aggiuntivi di registrazione incorporati nel codice seguente.

./source_files/template_hamiltonian_simulation.py (appended)
import os
os.environ["NUMBA_CACHE_DIR"] = "/data"

import datetime
import quimb.tensor
from scipy.optimize import OptimizeResult, minimize
from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit
from qiskit_addon_aqc_tensor.ansatz_generation import (
    generate_ansatz_from_circuit,
    AnsatzBlock,
)
from qiskit_addon_aqc_tensor.simulation import (
    tensornetwork_from_circuit,
    compute_overlap,
)
from qiskit_addon_aqc_tensor.simulation.quimb import QuimbSimulator
from qiskit_addon_aqc_tensor.objective import OneMinusFidelity

print("Hamiltonian:", hamiltonian)
print("Observable:", observable)
simulator_settings = QuimbSimulator(quimb.tensor.CircuitMPS, autodiff_backend="jax")

# Construct the AQC target circuit
aqc_target_circuit = initial_state.copy()
if aqc_evolution_time:
    aqc_target_circuit.compose(
        generate_time_evolution_circuit(
            hamiltonian,
            synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
            time=aqc_evolution_time,
        ),
        inplace=True,
    )

# Construct matrix-product state representation of the AQC target state
aqc_target_mps = tensornetwork_from_circuit(aqc_target_circuit, simulator_settings)
print("Target MPS maximum bond dimension:", aqc_target_mps.psi.max_bond())
output["target_bond_dimension"] = aqc_target_mps.psi.max_bond()

# Generate an ansatz and initial parameters from a Trotter circuit with fewer steps
aqc_good_circuit = initial_state.copy()
if aqc_evolution_time:
    aqc_good_circuit.compose(
        generate_time_evolution_circuit(
            hamiltonian,
            synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
            time=aqc_evolution_time,
        ),
        inplace=True,
    )
aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(aqc_good_circuit)
print("Number of AQC parameters:", len(aqc_initial_parameters))
output["num_aqc_parameters"] = len(aqc_initial_parameters)

# Calculate the fidelity of ansatz circuit vs. the target state, before optimization
good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)
starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2
print("Starting fidelity of AQC portion:", starting_fidelity)
output["aqc_starting_fidelity"] = starting_fidelity

# Optimize the ansatz parameters by using MPS calculations
def callback(intermediate_result: OptimizeResult):
    fidelity = 1 - intermediate_result.fun
    print(f"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}")
    if intermediate_result.fun < stopping_point:
        raise StopIteration


objective = OneMinusFidelity(aqc_target_mps, aqc_ansatz, simulator_settings)
stopping_point = 1.0 - aqc_stopping_fidelity

result = minimize(
    objective,
    aqc_initial_parameters,
    method="L-BFGS-B",
    jac=True,
    options={"maxiter": aqc_max_iterations},
    callback=callback,
)
if result.status not in (
    0,
    1,
    99,
):  # 0 => success; 1 => max iterations reached;
    # 99 => early termination via StopIteration
    raise RuntimeError(
        f"Optimization failed: {result.message} (status={result.status})"
    )
print(f"Done after {result.nit} iterations.")
output["num_iterations"] = result.nit
aqc_final_parameters = result.x
output["aqc_final_parameters"] = list(aqc_final_parameters)

# Construct an optimized circuit for initial portion of time evolution
aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)

# Calculate fidelity after optimization
aqc_final_mps = tensornetwork_from_circuit(aqc_final_circuit, simulator_settings)
aqc_fidelity = abs(compute_overlap(aqc_final_mps, aqc_target_mps)) ** 2
print("Fidelity of AQC portion:", aqc_fidelity)
output["aqc_fidelity"] = aqc_fidelity

# Construct final circuit, with remainder of time evolution
final_circuit = aqc_final_circuit.copy()
if remainder_evolution_time:
    remainder_circuit = generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=remainder_num_trotter_steps),
        time=remainder_evolution_time,
    )
    final_circuit.compose(remainder_circuit, inplace=True)

Ottimizzare il circuito finale per l'esecuzione

Dopo la parte AQC del flusso di lavoro, final_circuit viene transpilato per l'hardware come di consueto.

./source_files/template_hamiltonian_simulation.py (appended)
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler import generate_preset_pass_manager

service = QiskitRuntimeService()
backend = service.backend(backend_name)

# Transpile PUBs (circuits and observables) to match ISA
pass_manager = generate_preset_pass_manager(backend=backend, optimization_level=3)
isa_circuit = pass_manager.run(final_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)

isa_2qubit_depth = isa_circuit.depth(lambda x: x.operation.num_qubits == 2)
print("ISA circuit two-qubit depth:", isa_2qubit_depth)
output["twoqubit_depth"] = isa_2qubit_depth

Esci prima se utilizzi la modalità dry run

Se è stata selezionata la modalità Dry Run, il programma viene interrotto prima di essere eseguito sull'hardware. Questo può essere utile se, ad esempio, si vuole prima ispezionare la profondità a due qubit del circuito ISA prima di decidere di eseguirlo sull'hardware.

./source_files/template_hamiltonian_simulation.py (appended)
# Exit now if dry run; don't execute on hardware
if dry_run:
    import sys

    print("Exiting before hardware execution since `dry_run` is True.")
    save_result(output)
    sys.exit(0)

Eseguire il circuito sull'hardware

./source_files/template_hamiltonian_simulation.py (appended)
# ## Step 3: Execute quantum experiments on backend
from qiskit_ibm_runtime import EstimatorV2 as Estimator


estimator = Estimator(backend, options=estimator_options)

# Submit the underlying Estimator job. Note that this is not the
# actual function job.
job = estimator.run([(isa_circuit, isa_observable)])
print("Job ID:", job.job_id())
output["job_id"] = job.job_id()

# Wait until job is complete
hw_results = job.result()
hw_results_dicts = [pub_result.data.__dict__ for pub_result in hw_results]

# Save hardware results to serverless output dictionary
output["hw_results"] = hw_results_dicts

# Reorganize expectation values
hw_expvals = [pub_result_data["evs"].tolist()
    for pub_result_data in hw_results_dicts]

# Save expectation values to Qiskit Serverless
print("Hardware expectation values", hw_expvals)
output["hw_expvals"] = hw_expvals[0]

Salva l'output

Questo modello di funzione restituisce l'output rilevante a livello di dominio per questo flusso di lavoro di simulazione hamiltoniana (valori di aspettativa), oltre a importanti metadati generati lungo il percorso.

./source_files/template_hamiltonian_simulation.py (appended)
save_result(output)

Distribuisci la funzione su IBM Quantum Platform

Nella sezione precedente è stato creato un programma da eseguire in remoto. Il codice in questa sezione carica il programma su Qiskit Serverless.

Utilizzate qiskit-ibm-catalog per autenticarvi su QiskitServerless con la vostra chiave API, che potete trovare sulla dashboard di IBM Quantum Platform, e caricate il programma.

È possibile utilizzare save_account() per salvare le credenziali (vedere la guida Configurazione dell'account IBM Cloud ). Si noti che questa operazione scrive le credenziali nello stesso file di QiskitRuntimeService.save_account().

from qiskit_ibm_catalog import QiskitServerless, QiskitFunction

# Authenticate to the remote cluster and submit the pattern
# for remote execution
serverless = QiskitServerless()

Questo programma ha dipendenze personalizzate da pip . Aggiungerli a un array dependencies quando si costruisce l'istanza QiskitFunction :

template = QiskitFunction(
    title="template_hamiltonian_simulation",
    entrypoint="template_hamiltonian_simulation.py",
    working_dir="./source_files/",
    dependencies=[
        "qiskit-addon-utils~=0.1.0",
        "qiskit-addon-aqc-tensor[quimb-jax]~=0.1.2",
        "mergedeep==1.3.4",
    ],
)
serverless.upload(template)

Output:

QiskitFunction(template_hamiltonian_simulation)

Infine, per verificare se il programma è stato caricato con successo, utilizzare serverless.list():

serverless.list()

Output:

 QiskitFunction(template_hamiltonian_simulation),


Esegui il modello di funzione in remoto

Il modello di funzione è stato caricato, quindi è possibile eseguirlo in remoto con Qiskit Serverless. Per prima cosa, caricare il modello per nome:

template = serverless.load("template_hamiltonian_simulation")

Quindi, eseguire il modello con gli input a livello di dominio per la simulazione hamiltoniana. Questo esempio specifica un modello XXZ a 50 qubit con accoppiamenti casuali e uno stato e un'osservabile iniziali.

from itertools import chain
import numpy as np
from qiskit.quantum_info import SparsePauliOp

L = 50

# Generate the edge list for this spin-chain
edges = [(i, i + 1) for i in range(L - 1)]
# Generate an edge-coloring so we can make hw-efficient circuits
edges = edges[::2] + edges[1::2]

# Generate random coefficients for our XXZ Hamiltonian
np.random.seed(0)
Js = np.random.rand(L - 1) + 0.5 * np.ones(L - 1)

hamiltonian = SparsePauliOp.from_sparse_list(
    chain.from_iterable(
        [
            [
                ("XX", (i, j), Js[i] / 2),
                ("YY", (i, j), Js[i] / 2),
                ("ZZ", (i, j), Js[i]),
            ]
            for i, j in edges
        ]
    ),
    num_qubits=L,
)
observable = SparsePauliOp.from_sparse_list(
    [("ZZ", (L // 2 - 1, L // 2), 1.0)], num_qubits=L
)
from qiskit import QuantumCircuit

initial_state = QuantumCircuit(L)
for i in range(L):
    if i % 2:
        initial_state.x(i)
job = template.run(
    dry_run=True,
    initial_state=initial_state,
    hamiltonian=hamiltonian,
    observable=observable,
    backend_name="ibm_fez",
    estimator_options={},
    aqc_evolution_time=0.2,
    aqc_ansatz_num_trotter_steps=1,
    aqc_target_num_trotter_steps=32,
    remainder_evolution_time=0.2,
    remainder_num_trotter_steps=4,
    aqc_max_iterations=300,
)
print(job.job_id)

Output:

853b0edb-d63f-4629-be71-398b6dcf33cb

Controllare lo stato del lavoro:

job.status()

Output:

'QUEUED'

Dopo l'esecuzione del lavoro, è possibile recuperare i registri creati dalle uscite di print() . Questi possono fornire informazioni utili sull'avanzamento del flusso di lavoro della simulazione hamiltoniana. Ad esempio, il valore della funzione obiettivo durante la componente iterativa del CQA, o la profondità di due qubit del circuito ISA finale destinato all'esecuzione su hardware.

print(job.logs())

Output:

No logs yet.

Blocca il resto del programma finché non è disponibile un risultato. Al termine del lavoro, è possibile recuperare i risultati. Questi includono l'output a livello di dominio della simulazione hamiltoniana (valore di aspettativa) e metadati utili.

result = job.result()

del result[
    "aqc_final_parameters"
]  # the list is too long to conveniently display here
result

Output:

{'target_bond_dimension': 5,
 'num_aqc_parameters': 816,
 'aqc_starting_fidelity': 0.9914382555614002,
 'num_iterations': 72,
 'aqc_fidelity': 0.9998108844412502,
 'twoqubit_depth': 33}

Al termine del lavoro, sarà disponibile l'intero output di registrazione.

print(job.logs())

Output:

2024-12-17 14:50:15,580	INFO job_manager.py:531 -- Runtime env is setting up.
estimator_options = {
    "resilience": {
        "measure_mitigation": true,
        "zne_mitigation": true,
        "zne": {
            "amplifier": "gate_folding",
            "noise_factors": [
                1,
                2,
                3
            ],
            "extrapolated_noise_factors": [
                0.0,
                0.1,
                0.2,
                0.30000000000000004,
                0.4,
                0.5,
                0.6000000000000001,
                0.7000000000000001,
                0.8,
                0.9,
                1.0,
                1.1,
                1.2000000000000002,
                1.3,
                1.4000000000000001,
                1.5,
                1.6,
                1.7000000000000002,
                1.8,
                1.9000000000000001,
                2.0,
                2.1,
                2.2,
                2.3000000000000003,
                2.4000000000000004,
                2.5,
                2.6,
                2.7,
                2.8000000000000003,
                2.9000000000000004,
                3.0
            ],
            "extrapolator": [
                "exponential",
                "linear",
                "fallback"
            ]
        },
        "measure_noise_learning": {
            "num_randomizations": 512,
            "shots_per_randomization": 512
        }
    },
    "twirling": {
        "enable_gates": true,
        "enable_measure": true,
        "num_randomizations": 300,
        "shots_per_randomization": 100,
        "strategy": "active"
    }
}
Hamiltonian: SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYY', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'XXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'YYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'ZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IXXIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IYYIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII', 'IZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
              coeffs=[0.52440675+0.j, 0.52440675+0.j, 1.0488135 +0.j, 0.55138169+0.j,
 0.55138169+0.j, 1.10276338+0.j, 0.4618274 +0.j, 0.4618274 +0.j,
 0.9236548 +0.j, 0.46879361+0.j, 0.46879361+0.j, 0.93758721+0.j,
 0.73183138+0.j, 0.73183138+0.j, 1.46366276+0.j, 0.64586252+0.j,
 0.64586252+0.j, 1.29172504+0.j, 0.53402228+0.j, 0.53402228+0.j,
 1.06804456+0.j, 0.28551803+0.j, 0.28551803+0.j, 0.57103606+0.j,
 0.2601092 +0.j, 0.2601092 +0.j, 0.5202184 +0.j, 0.63907838+0.j,
 0.63907838+0.j, 1.27815675+0.j, 0.73930917+0.j, 0.73930917+0.j,
 1.47861834+0.j, 0.48073968+0.j, 0.48073968+0.j, 0.96147936+0.j,
 0.30913721+0.j, 0.30913721+0.j, 0.61827443+0.j, 0.32167664+0.j,
 0.32167664+0.j, 0.64335329+0.j, 0.51092416+0.j, 0.51092416+0.j,
 1.02184832+0.j, 0.38227781+0.j, 0.38227781+0.j, 0.76455561+0.j,
 0.47807517+0.j, 0.47807517+0.j, 0.95615033+0.j, 0.2593949 +0.j,
 0.2593949 +0.j, 0.5187898 +0.j, 0.55604786+0.j, 0.55604786+0.j,
 1.11209572+0.j, 0.72187404+0.j, 0.72187404+0.j, 1.44374808+0.j,
 0.42975395+0.j, 0.42975395+0.j, 0.8595079 +0.j, 0.5988156 +0.j,
 0.5988156 +0.j, 1.1976312 +0.j, 0.58338336+0.j, 0.58338336+0.j,
 1.16676672+0.j, 0.35519128+0.j, 0.35519128+0.j, 0.71038256+0.j,
 0.40771418+0.j, 0.40771418+0.j, 0.81542835+0.j, 0.60759468+0.j,
 0.60759468+0.j, 1.21518937+0.j, 0.52244159+0.j, 0.52244159+0.j,
 1.04488318+0.j, 0.57294706+0.j, 0.57294706+0.j, 1.14589411+0.j,
 0.6958865 +0.j, 0.6958865 +0.j, 1.391773  +0.j, 0.44172076+0.j,
 0.44172076+0.j, 0.88344152+0.j, 0.51444746+0.j, 0.51444746+0.j,
 1.02889492+0.j, 0.71279832+0.j, 0.71279832+0.j, 1.42559664+0.j,
 0.29356465+0.j, 0.29356465+0.j, 0.5871293 +0.j, 0.66630992+0.j,
 0.66630992+0.j, 1.33261985+0.j, 0.68500607+0.j, 0.68500607+0.j,
 1.37001215+0.j, 0.64957928+0.j, 0.64957928+0.j, 1.29915856+0.j,
 0.64026459+0.j, 0.64026459+0.j, 1.28052918+0.j, 0.56996051+0.j,
 0.56996051+0.j, 1.13992102+0.j, 0.72233446+0.j, 0.72233446+0.j,
 1.44466892+0.j, 0.45733097+0.j, 0.45733097+0.j, 0.91466194+0.j,
 0.63711684+0.j, 0.63711684+0.j, 1.27423369+0.j, 0.53421697+0.j,
 0.53421697+0.j, 1.06843395+0.j, 0.55881775+0.j, 0.55881775+0.j,
 1.1176355 +0.j, 0.558467  +0.j, 0.558467  +0.j, 1.116934  +0.j,
 0.59091015+0.j, 0.59091015+0.j, 1.1818203 +0.j, 0.46851598+0.j,
 0.46851598+0.j, 0.93703195+0.j, 0.28011274+0.j, 0.28011274+0.j,
 0.56022547+0.j, 0.58531893+0.j, 0.58531893+0.j, 1.17063787+0.j,
 0.31446315+0.j, 0.31446315+0.j, 0.6289263 +0.j])
Observable: SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIII'],
              coeffs=[1.+0.j])
Target MPS maximum bond dimension: 5
Number of AQC parameters: 816
Starting fidelity of AQC portion: 0.9914382555614002
2024-12-17 14:52:23.400028 Intermediate result: Fidelity 0.99764093
2024-12-17 14:52:23.429669 Intermediate result: Fidelity 0.99788003
2024-12-17 14:52:23.459674 Intermediate result: Fidelity 0.99795970
2024-12-17 14:52:23.489666 Intermediate result: Fidelity 0.99799067
2024-12-17 14:52:23.518545 Intermediate result: Fidelity 0.99803401
2024-12-17 14:52:23.546952 Intermediate result: Fidelity 0.99809821
2024-12-17 14:52:23.575271 Intermediate result: Fidelity 0.99824660
2024-12-17 14:52:23.604049 Intermediate result: Fidelity 0.99845326
2024-12-17 14:52:23.632709 Intermediate result: Fidelity 0.99870497
2024-12-17 14:52:23.660527 Intermediate result: Fidelity 0.99891442
2024-12-17 14:52:23.688273 Intermediate result: Fidelity 0.99904488
2024-12-17 14:52:23.716105 Intermediate result: Fidelity 0.99914438
2024-12-17 14:52:23.744336 Intermediate result: Fidelity 0.99922827
2024-12-17 14:52:23.773399 Intermediate result: Fidelity 0.99929071
2024-12-17 14:52:23.801482 Intermediate result: Fidelity 0.99932432
2024-12-17 14:52:23.830466 Intermediate result: Fidelity 0.99936460
2024-12-17 14:52:23.860738 Intermediate result: Fidelity 0.99938891
2024-12-17 14:52:23.889958 Intermediate result: Fidelity 0.99940607
2024-12-17 14:52:23.918703 Intermediate result: Fidelity 0.99941965
2024-12-17 14:52:23.949744 Intermediate result: Fidelity 0.99944337
2024-12-17 14:52:23.980871 Intermediate result: Fidelity 0.99946875
2024-12-17 14:52:24.012124 Intermediate result: Fidelity 0.99949009
2024-12-17 14:52:24.044359 Intermediate result: Fidelity 0.99952191
2024-12-17 14:52:24.075840 Intermediate result: Fidelity 0.99953669
2024-12-17 14:52:24.106303 Intermediate result: Fidelity 0.99955242
2024-12-17 14:52:24.139329 Intermediate result: Fidelity 0.99958412
2024-12-17 14:52:24.169725 Intermediate result: Fidelity 0.99960176
2024-12-17 14:52:24.198749 Intermediate result: Fidelity 0.99961606
2024-12-17 14:52:24.227874 Intermediate result: Fidelity 0.99963811
2024-12-17 14:52:24.256818 Intermediate result: Fidelity 0.99964383
2024-12-17 14:52:24.285889 Intermediate result: Fidelity 0.99964717
2024-12-17 14:52:24.315228 Intermediate result: Fidelity 0.99966064
2024-12-17 14:52:24.345322 Intermediate result: Fidelity 0.99966517
2024-12-17 14:52:24.374921 Intermediate result: Fidelity 0.99967089
2024-12-17 14:52:24.404309 Intermediate result: Fidelity 0.99968305
2024-12-17 14:52:24.432664 Intermediate result: Fidelity 0.99968889
2024-12-17 14:52:24.461639 Intermediate result: Fidelity 0.99969997
2024-12-17 14:52:24.491244 Intermediate result: Fidelity 0.99971666
2024-12-17 14:52:24.520354 Intermediate result: Fidelity 0.99972441
2024-12-17 14:52:24.549965 Intermediate result: Fidelity 0.99973561
2024-12-17 14:52:24.583464 Intermediate result: Fidelity 0.99973811
2024-12-17 14:52:24.617537 Intermediate result: Fidelity 0.99974074
2024-12-17 14:52:24.652247 Intermediate result: Fidelity 0.99974467
2024-12-17 14:52:24.686831 Intermediate result: Fidelity 0.99974991
2024-12-17 14:52:24.725476 Intermediate result: Fidelity 0.99975230
2024-12-17 14:52:24.764637 Intermediate result: Fidelity 0.99975373
2024-12-17 14:52:24.802499 Intermediate result: Fidelity 0.99975552
2024-12-17 14:52:24.839960 Intermediate result: Fidelity 0.99975885
2024-12-17 14:52:24.877472 Intermediate result: Fidelity 0.99976469
2024-12-17 14:52:24.916233 Intermediate result: Fidelity 0.99976517
2024-12-17 14:52:24.993750 Intermediate result: Fidelity 0.99976875
2024-12-17 14:52:25.034953 Intermediate result: Fidelity 0.99976887
2024-12-17 14:52:25.076197 Intermediate result: Fidelity 0.99977244
2024-12-17 14:52:25.112340 Intermediate result: Fidelity 0.99977638
2024-12-17 14:52:25.149947 Intermediate result: Fidelity 0.99977828
2024-12-17 14:52:25.190049 Intermediate result: Fidelity 0.99978174
2024-12-17 14:52:25.310903 Intermediate result: Fidelity 0.99978222
2024-12-17 14:52:25.347512 Intermediate result: Fidelity 0.99978508
2024-12-17 14:52:25.385201 Intermediate result: Fidelity 0.99978543
2024-12-17 14:52:25.457436 Intermediate result: Fidelity 0.99978770
2024-12-17 14:52:25.497133 Intermediate result: Fidelity 0.99978818
2024-12-17 14:52:25.541179 Intermediate result: Fidelity 0.99978913
2024-12-17 14:52:25.584791 Intermediate result: Fidelity 0.99978937
2024-12-17 14:52:25.621484 Intermediate result: Fidelity 0.99979068
2024-12-17 14:52:25.655847 Intermediate result: Fidelity 0.99979211
2024-12-17 14:52:25.691710 Intermediate result: Fidelity 0.99979700
2024-12-17 14:52:25.767711 Intermediate result: Fidelity 0.99979759
2024-12-17 14:52:25.804517 Intermediate result: Fidelity 0.99979807
2024-12-17 14:52:25.839394 Intermediate result: Fidelity 0.99980236
2024-12-17 14:52:25.874438 Intermediate result: Fidelity 0.99980296
2024-12-17 14:52:25.909900 Intermediate result: Fidelity 0.99980320
2024-12-17 14:52:26.713044 Intermediate result: Fidelity 0.99980320
Done after 72 iterations.
Fidelity of AQC portion: 0.9998108844412502
ISA circuit two-qubit depth: 33
Exiting before hardware execution since `dry_run` is True.


Passi successivi

Suggerimenti

Per un'immersione più approfondita nell'addon Qiskit AQC-Tensor, consultate il tutorial Improved Trotterized Time Evolution with Approximate Quantum Compilation o il repository qiskit-addon-aqc-tensor.

  • Ecco l'intero sorgente di ./source_files/template_hamiltonian_simulation.py come blocco di codice.

    ./source_files/template_hamiltonian_simulation_full.py
    from qiskit import QuantumCircuit
    from qiskit_serverless import get_arguments, save_result
    
    
    # Extract parameters from arguments
    #
    # Do this at the top of the program so it fails early
    # if any required arguments are missing or invalid.
    
    arguments = get_arguments()
    
    dry_run = arguments.get("dry_run", False)
    backend_name = arguments["backend_name"]
    
    aqc_evolution_time = arguments["aqc_evolution_time"]
    aqc_ansatz_num_trotter_steps = arguments["aqc_ansatz_num_trotter_steps"]
    aqc_target_num_trotter_steps = arguments["aqc_target_num_trotter_steps"]
    
    remainder_evolution_time = arguments["remainder_evolution_time"]
    remainder_num_trotter_steps = arguments["remainder_num_trotter_steps"]
    
    # Stop if this fidelity is achieved
    aqc_stopping_fidelity = arguments.get("aqc_stopping_fidelity", 1.0)
    # Stop after this number of iterations, even if stopping fidelity is not achieved
    aqc_max_iterations = arguments.get("aqc_max_iterations", 500)
    
    hamiltonian = arguments["hamiltonian"]
    observable = arguments["observable"]
    initial_state = arguments.get("initial_state", QuantumCircuit(hamiltonian.num_qubits))
    
    import numpy as np
    import json
    from mergedeep import merge
    
    
    # Configure `EstimatorOptions` to control the hardware experiment's parameters
    #
    # Set default options
    estimator_default_options = {
        "resilience": {
            "measure_mitigation": True,
            "zne_mitigation": True,
            "zne": {
                "amplifier": "gate_folding",
                "noise_factors": [1, 2, 3],
                "extrapolated_noise_factors": list(np.linspace(0, 3, 31)),
                "extrapolator": ["exponential", "linear", "fallback"],
            },
            "measure_noise_learning": {
                "num_randomizations": 512,
                "shots_per_randomization": 512,
            },
        },
        "twirling": {
            "enable_gates": True,
            "enable_measure": True,
            "num_randomizations": 300,
            "shots_per_randomization": 100,
            "strategy": "active",
        },
    }
    # Merge with user-provided options
    estimator_options = merge(
        arguments.get("estimator_options", {}), estimator_default_options
    )
    
    print("estimator_options =", json.dumps(estimator_options, indent=4))
    
    # Perform parameter validation
    
    if not 0.0 < aqc_stopping_fidelity <= 1.0:
        raise ValueError(
            f"Invalid stopping fidelity: {aqc_stopping_fidelity}.  "
            It must be a positive float no greater than 1."
        )
    
    output = {}
    
    import os
    os.environ["NUMBA_CACHE_DIR"] = "/data"
    
    import datetime
    import quimb.tensor
    from scipy.optimize import OptimizeResult, minimize
    from qiskit.synthesis import SuzukiTrotter
    from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit
    from qiskit_addon_aqc_tensor.ansatz_generation import (
        generate_ansatz_from_circuit,
        AnsatzBlock,
    )
    from qiskit_addon_aqc_tensor.simulation import (
        tensornetwork_from_circuit,
        compute_overlap,
    )
    from qiskit_addon_aqc_tensor.simulation.quimb import QuimbSimulator
    from qiskit_addon_aqc_tensor.objective import OneMinusFidelity
    
    print("Hamiltonian:", hamiltonian)
    print("Observable:", observable)
    simulator_settings = QuimbSimulator(quimb.tensor.CircuitMPS, autodiff_backend="jax")
    
    # Construct the AQC target circuit
    aqc_target_circuit = initial_state.copy()
    if aqc_evolution_time:
        aqc_target_circuit.compose(
            generate_time_evolution_circuit(
                hamiltonian,
                synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
                time=aqc_evolution_time,
            ),
            inplace=True,
        )
    
    # Construct matrix-product state representation of the AQC target state
    aqc_target_mps = tensornetwork_from_circuit(aqc_target_circuit, simulator_settings)
    print("Target MPS maximum bond dimension:", aqc_target_mps.psi.max_bond())
    output["target_bond_dimension"] = aqc_target_mps.psi.max_bond()
    
    # Generate an ansatz and initial parameters from a Trotter circuit with fewer steps
    aqc_good_circuit = initial_state.copy()
    if aqc_evolution_time:
        aqc_good_circuit.compose(
            generate_time_evolution_circuit(
                hamiltonian,
                synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
                time=aqc_evolution_time,
            ),
            inplace=True,
        )
    aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(aqc_good_circuit)
    print("Number of AQC parameters:", len(aqc_initial_parameters))
    output["num_aqc_parameters"] = len(aqc_initial_parameters)
    
    # Calculate the fidelity of ansatz circuit vs. the target state, before optimization
    good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)
    starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2
    print("Starting fidelity of AQC portion:", starting_fidelity)
    output["aqc_starting_fidelity"] = starting_fidelity
    
    # Optimize the ansatz parameters by using MPS calculations
    def callback(intermediate_result: OptimizeResult):
        fidelity = 1 - intermediate_result.fun
        print(f"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}")
        if intermediate_result.fun < stopping_point:
            raise StopIteration
    
    
    objective = OneMinusFidelity(aqc_target_mps, aqc_ansatz, simulator_settings)
    stopping_point = 1.0 - aqc_stopping_fidelity
    
    result = minimize(
        objective,
        aqc_initial_parameters,
        method="L-BFGS-B",
        jac=True,
        options={"maxiter": aqc_max_iterations},
        callback=callback,
    )
    if result.status not in (
        0,
        1,
        99,
    ):  # 0 => success; 1 => max iterations reached; 99 => early termination via StopIteration
        raise RuntimeError(
            f"Optimization failed: {result.message} (status={result.status})"
        )
    print(f"Done after {result.nit} iterations.")
    output["num_iterations"] = result.nit
    aqc_final_parameters = result.x
    output["aqc_final_parameters"] = list(aqc_final_parameters)
    
    # Construct an optimized circuit for initial portion of time evolution
    aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
    
    # Calculate fidelity after optimization
    aqc_final_mps = tensornetwork_from_circuit(aqc_final_circuit, simulator_settings)
    aqc_fidelity = abs(compute_overlap(aqc_final_mps, aqc_target_mps)) ** 2
    print("Fidelity of AQC portion:", aqc_fidelity)
    output["aqc_fidelity"] = aqc_fidelity
    
    # Construct final circuit, with remainder of time evolution
    final_circuit = aqc_final_circuit.copy()
    if remainder_evolution_time:
        remainder_circuit = generate_time_evolution_circuit(
            hamiltonian,
            synthesis=SuzukiTrotter(reps=remainder_num_trotter_steps),
            time=remainder_evolution_time,
        )
        final_circuit.compose(remainder_circuit, inplace=True)
    
    from qiskit.transpiler import generate_preset_pass_manager
    from qiskit_ibm_catalog import QiskitFunctionsCatalog
    
    service = QiskitRuntimeService()
    backend = service.backend(backend_name)
    
    # Transpile PUBs (circuits and observables) to match ISA
    pass_manager = generate_preset_pass_manager(backend=backend, optimization_level=3)
    isa_circuit = pass_manager.run(final_circuit)
    isa_observable = observable.apply_layout(isa_circuit.layout)
    
    isa_2qubit_depth = isa_circuit.depth(lambda x: x.operation.num_qubits == 2)
    print("ISA circuit two-qubit depth:", isa_2qubit_depth)
    output["twoqubit_depth"] = isa_2qubit_depth
    
    # Exit now if dry run; don't execute on hardware
    if dry_run:
        import sys
    
        print("Exiting before hardware execution since `dry_run` is True.")
        save_result(output)
        sys.exit(0)
    
    # ## Step 3: Execute quantum experiments on backend
    from qiskit_ibm_runtime import EstimatorV2 as Estimator
    
    
    estimator = Estimator(backend, options=estimator_options)
    
    # Submit the underlying Estimator job. Note that this is not the
    # actual function job.
    job = estimator.run([(isa_circuit, isa_observable)])
    print("Job ID:", job.job_id())
    output["job_id"] = job.job_id()
    
    # Wait until job is complete
    hw_results = job.result()
    hw_results_dicts = [pub_result.data.__dict__ for pub_result in hw_results]
    
    # Save hardware results to serverless output dictionary
    output["hw_results"] = hw_results_dicts
    
    # Reorganize expectation values
    hw_expvals = [pub_result_data["evs"].tolist()
        for pub_result_data in hw_results_dicts]
    
    # Save expectation values to Qiskit Serverless
    output["hw_expvals"] = hw_expvals[0]
    
    save_result(output)
Questa pagina è stata utile?
Segnala un bug, un errore di battitura o richiedi contenuti su GitHub.