Esquema

La manera més senzilla de construir un esquema comú és fer servir les funcions d’ajuda:

  • linear: Interpolació lineal entre dos Hamiltonians.

  • quadratic: Interpolació quadràtica entre dos Hamiltonians.

  • polynomial: Interpolació polinomial de grau arbitrari entre dos Hamiltonians.

  • sinusoidal: Interpolació sinusoïdal entre dos Hamiltonians.

  • constant: Coeficient constant per a un sol Hamiltonià.

  • chained_linear: Encadenament lineal de múltiples Hamiltonians.

Per exemple, per crear un esquema lineal que interpola entre un Hamiltonià conductor i un Hamiltonià de problema en un temps de 10 unitats:

from qilisdk.analog import Schedule, X, Z

H1 = X(0) + X(1)
H2 = Z(0) * Z(1)

schedule = Schedule.linear(H1, H2, 10.0)
schedule.draw()
../../_images/schedule_light.svg ../../_images/schedule_dark.svg

Per a schedules més complexos, podeu utilitzar la classe Schedule directament, la qual ofereix una interfície flexible per definir completament els coeficients de l’Hamiltonià dependents del temps. La classe Schedule mapeja punts temporals a coeficients de Hamiltonian. Els coeficients poden ser nombres, paràmetres/expressions, o funcions invocables del temps, i podeu definir-los en punts discrets o sobre intervals que es mostregen automàticament.

Arguments principals

  • dt (float): resolució de les mostres temporals. El valor per defecte és 0.1.

  • hamiltonians (dict[str, Hamiltonian]): Mapa d’etiquetes a instàncies de Hamiltonian.

  • coefficients (dict[str, dict]): Mapeig de l’etiqueta de l’Hamiltonià a un diccionari de definició temporal. Cada clau és un punt temporal (float/paràmetre/expressió) o una tupla de 2 elements que defineix un interval; cada valor pot ser:
    • el coeficient del Hamiltonià en aquell moment

    • o un callable que retorna un coeficient. Aquest callable pot acceptar un paràmetre t que serà substituït pel temps. A més, qualsevol altre paràmetre passat a aquest callable ha de tenir un valor per defecte o tenir el seu valor especificat en **kwargs.

  • interpolation (Interpolation): comportament LINEAR (per defecte) o STEP entre els punts proporcionats.

  • total_time (float | Parameter | Expression | None): Temps màxim opcional que reescala tots els punts temporals preservant les posicions relatives.

  • extrapolate (bool): Si cal extrapolar un coeficient fora dels seus propis punts temporals. Per defecte és False, la qual cosa significa que el coeficient es mantindrà constant fora dels seus propis punts temporals.

Nota

Quan es col·loquen paràmetres a l’eix temporal (p. ex., com a punts temporals o extrems d’interval), l’esquema restringeix automàticament aquells paràmetres perquè es mantinguin entre els seus punts temporals veïns, de manera que l’ordre de la línia de temps continua sent vàlid.

Exemple 1: Coeficients callables amb mostreig per intervals

from qilisdk.analog import Schedule, X, Z
from qilisdk.analog.schedule import Interpolation

h_driver = X(0) + X(1)
h_problem = Z(0) * Z(1)

schedule = Schedule(
    hamiltonians={"driver": h_driver, "problem": h_problem},
    coefficients={
        "driver": {(0.0, 10.0): lambda t: 1 - t / 10.0},
        "problem": {(0.0, 10.0): lambda t: t / 10.0},
    },
    dt=0.5,
    interpolation=Interpolation.LINEAR,
)
schedule.draw()

Exemple 2: Interpolació per passos i reescalat del temps màxim

from qilisdk.analog import Schedule, Z
from qilisdk.analog.schedule import Interpolation
from qilisdk.utils.visualization.style import ScheduleStyle

h = Z(0)
schedule = Schedule(
    hamiltonians={"h": h},
    coefficients={"h": {0.0: 1.0, 5.0: 0.2}},
    dt=0.01,
    interpolation=Interpolation.STEP,
)

# Later, shorten the experiment to 3s without redefining points
schedule.draw(ScheduleStyle(title="Before Time Scaling"))
schedule.scale_max_time(3.0)
schedule.draw(ScheduleStyle(title="After Time Scaling"))
print("Time grid:", schedule.tlist)
print("Coeff at t=1.5:", schedule.coefficients["h"][1.5])

Nota

La funció draw mostra 1/dt punts de l’esquema; per tant, per augmentar la resolució del gràfic podeu reduir dt.

Esquemes parametritzats

Els coeficients de Schedule poden ser simbòlics, cosa que permet bucles d’optimització clàssica o experiments que exploren una família de perfils temporals. Els coeficients poden ser instàncies de Parameter o expressions algebraiques (Expression) construïdes a partir de paràmetres. El schedule registra cada paràmetre que troba perquè pugueu consultar-los o modificar-los més endavant.

from qilisdk.analog import Schedule, Z
from qilisdk.core import Parameter, GreaterThanOrEqual

gamma = Parameter("gamma", value=0.5, bounds=(0.0, 1.0))
T = Parameter("T", value=10.0, bounds=(1.0, 20.0))

schedule = Schedule(
    hamiltonians={"problem": Z(0)},
    coefficients={"problem": {(0.0, T): lambda t: gamma * t}},
    dt=0.1,
    total_time=T,
)

schedule.get_parameters()

schedule.set_parameters({"gamma": 0.7})
print(schedule.get_parameter_names())   # ['gamma', 'T']
print(schedule.get_constraints())       # [0 <= T]

Nota

Per a esquemes, Hamiltonians i interpoladors, feu servir get_parameters i els mètodes d’accés relacionats per inspeccionar l’estat dels paràmetres.

Visualització d’esquemes

Tot i que Schedule.draw() és útil per visualitzar els coeficients dels Hamiltonians al llarg del temps, també podeu fer servir Schedule.draw_eigenvalues() per visualitzar com canvien els valors propis del Hamiltonià global al llarg del temps. Això només es pot fer per a sistemes petits (posem per cas, 8 qubits o menys), ja que requereix diagonalitzar el Hamiltonià a cada pas de temps, però pot ser molt útil per veure com evoluciona la separació entre l’estat fonamental i el primer estat excitat. Per exemple:

from qilisdk.analog import Schedule, X, Z

h_driver = -(X(0) + X(1))
h_problem = Z(0) * Z(1)

schedule = Schedule.linear(h_driver, h_problem, total_time=10.0, dt=0.1)
schedule.draw_eigenvalues()
../../_images/schedule_eigenvalues.svg ../../_images/schedule_eigenvalues_dark.svg

Si comencem en l’estat fonamental del Hamiltonià conductor (la línia inferior, a l’extrem esquerre) i després evolucionem lentament, hauríem d’acabar en l’estat fonamental del Hamiltonià de problema (a l’extrem dret). Per comprovar-ho, podem simular l’evolució i després incloure els estats intermedis en el gràfic:

from qilisdk.functionals import AnalogEvolution
from qilisdk.backends import QiliSim
from qilisdk.readout import Readout
from qilisdk.core import InitialState

backend = QiliSim()
evolution = AnalogEvolution(
    schedule=schedule,
    initial_state=InitialState.UNIFORM,
    store_intermediate_results=True
)
readout = Readout().with_state_tomography()
results = backend.execute(evolution, readout)

schedule.draw_eigenvalues(
    intermediate_states=results.get_intermediate_states(),
    show_overlaps=True
)
../../_images/schedule_eigenvalues_state.svg ../../_images/schedule_eigenvalues_state_dark.svg

Aquí podem veure que l’estat va començar correctament en l’estat fonamental del Hamiltonià inicial i després va evolucionar cap a l’estat fonamental del Hamiltonià final. El percentatge de solapament mostra que una petita part de l’estat es va filtrar cap a un estat d’ordre superior, però això és només una conseqüència del temps d’evolució; una evolució més llarga/lenta ho reduiria.