Esquema

La forma más sencilla de construir un schedule común es utilizar las funciones auxiliares:

  • linear: Interpolación lineal entre dos Hamiltonianos.

  • quadratic: Interpolación cuadrática entre dos Hamiltonianos.

  • polynomial: Interpolación polinómica de grado arbitrario entre dos Hamiltonianos.

  • sinusoidal: Interpolación sinusoidal entre dos Hamiltonianos.

  • constant: Coeficiente constante para un solo Hamiltoniano.

  • chained_linear: Encadenamiento lineal de múltiples Hamiltonianos.

Por ejemplo, para crear un schedule lineal que interpola entre un Hamiltoniano conductor y un Hamiltoniano de problema durante un tiempo de 10 unidades:

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

For more complex schedules, you can use the Schedule class directly, which provides a flexible interface to fully define time-dependent Hamiltonian coefficients. The Schedule class maps time points to Hamiltonian coefficients. Coefficients can be numbers, parameters/terms, or callables of time, and you can define them at discrete points or over intervals that are sampled automatically.

Argumentos clave

  • dt (float): resolución de las muestras temporales. El valor predeterminado es 0.1.

  • hamiltonians (dict[str, Hamiltonian]): Mapa de etiquetas a instancias de Hamiltonian.

  • coefficients (dict[str, dict]): Mapping from Hamiltonian label to a time-definition dictionary. Each key is either a time point (float/parameter/term) or a 2-tuple defining an interval; each value can be:
    • el coeficiente del Hamiltoniano en ese instante

    • o una función invocable que devuelva un coeficiente. Esta función puede recibir un parámetro t que será sustituido por el tiempo. Además, cualquier otro parámetro pasado a esta función debe tener un valor predeterminado o tener su valor especificado en los **kwargs.

  • interpolation (Interpolation): comportamiento LINEAR (predeterminado) o STEP entre los puntos proporcionados.

  • total_time (float | Parameter | Term | None): Optional max time that rescales all time points while preserving relative positions.

Nota

Cuando se colocan parámetros en el eje temporal (p. ej., como puntos temporales o extremos de intervalos), el schedule restringe automáticamente esos parámetros para que permanezcan entre sus puntos temporales vecinos, de modo que el orden de la línea temporal siga siendo válido.

Ejemplo 1: Coeficientes invocables con muestreo por intervalos

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()

Ejemplo 2: Interpolación por pasos y reescalado del tiempo máximo

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ón draw muestrea 1/dt puntos del schedule; por lo tanto, para obtener mayor resolución en el gráfico se puede reducir dt.

Schedules parametrizados

Schedule coefficients can be symbolic, enabling classical optimization loops or experiments that scan over a family of time profiles. Coefficients can be instances of Parameter or algebraic expressions (Term) built from parameters. The schedule tracks every parameter it encounters so you can query or set them later.

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

Para schedules, Hamiltonianos e interpoladores, use get_parameters y los métodos de acceso relacionados para inspeccionar el estado de los parámetros.

Visualización de schedules

Aunque Schedule.draw() resulta útil para visualizar los coeficientes de los Hamiltonianos a lo largo del tiempo, también puede utilizar Schedule.draw_eigenvalues() para visualizar cómo cambian los valores propios del Hamiltoniano global a lo largo del tiempo. Esto solo puede hacerse para sistemas pequeños (digamos, 8 qubits o menos), ya que requiere diagonalizar el Hamiltoniano en cada paso de tiempo, pero puede ser muy útil para ver cómo evoluciona la separación entre el estado fundamental y el primer estado excitado. Por ejemplo:

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 comenzamos en el estado fundamental del Hamiltoniano conductor (la línea inferior, en el extremo izquierdo) y luego evolucionamos lentamente, deberíamos terminar en el estado fundamental del Hamiltoniano de problema (en el extremo derecho). Para comprobarlo, podemos simular la evolución y luego incluir los estados intermedios en el gráfico:

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í podemos ver que el estado comenzó correctamente en el estado fundamental del Hamiltoniano inicial y luego evolucionó hacia el estado fundamental del Hamiltoniano final. El porcentaje de solapamiento muestra que una pequeña parte del estado se filtró hacia un estado de orden superior, pero esto es solo consecuencia del tiempo de evolución; una evolución más larga/lenta lo reduciría.