Programas Variacionales
El funcional VariationalProgram reúne los componentes necesarios para un algoritmo cuántico variacional. Acepta un functional primitivo parametrizado, un optimizador y una función de coste. Al llamar a execute(), evalúa el functional repetidamente con parámetros actualizados, alimenta el FunctionalResult resultante en la función de coste suministrada y finalmente devuelve un VariationalProgramResult. Las restricciones de parámetros (desigualdades/igualdades sobre parámetros) se adjuntan en este nivel mediante el argumento parameter_constraints; este es el lugar para imponer relaciones como theta >= phi o límites entre parámetros en todos los functionals de QiliSDK. Solo los parámetros marcados como entrenables se optimizan durante este bucle.
Parámetros
functional (
PrimitiveFunctional): Primitivo parametrizado a optimizar (por ejemplo,DigitalPropagationoAnalogEvolution).optimizer (
Optimizer): Optimizador clásico que propone nuevos valores de parámetros y opcionalmente almacena los iterados intermedios.cost_function (
CostFunction): Objeto que transforma los resultados del functional en un coste escalar; frecuentemente construido a partir de unModel.store_intermediate_results (bool, opcional): Cuando es True, el optimizador conserva los pasos intermedios, que se exponen mediante
intermediate_results.parameter_constraints (list[
ComparisonTerm], opcional): Restricciones sobre los parámetros del functional (p. ej.,theta >= 0.5) evaluadas antes de cada actualización del optimizador. Este es el punto de entrada admitido para imponer relaciones entre parámetros en QiliSDK.
Retorna
VariationalProgramResult: Recuperaoptimal_cost,optimal_parameters, y la salida final del functional empaquetada enoptimal_execution_results.
Ejemplo de Uso (con el Backend QiliSim)
import numpy as np
from qilisdk.backends import QiliSim
from qilisdk.core.model import Model, ObjectiveSense
from qilisdk.core.variables import LEQ, BinaryVariable
from qilisdk.cost_functions.model_cost_function import ModelCostFunction
from qilisdk.digital import CNOT, U3, HardwareEfficientAnsatz
from qilisdk.functionals import DigitalPropagation
from qilisdk.functionals.variational_program import VariationalProgram
from qilisdk.optimizers.scipy_optimizer import SciPyOptimizer
from qilisdk.readout import Readout
values = [2, 3, 7]
weights = [1, 3, 3]
max_weight = 4
binary_var = [BinaryVariable(f"b{i}") for i in range(len(values))]
model = Model("Knapsack")
model.set_objective(sum(binary_var[i] * values[i] for i in range(len(values))), sense=ObjectiveSense.MAXIMIZE)
model.add_constraint("max_weights", LEQ(sum(binary_var[i] * weights[i] for i in range(len(weights))), max_weight))
ansatz = HardwareEfficientAnsatz(
nqubits=3, layers=4, connectivity="Circular", one_qubit_gate=U3, two_qubit_gate=CNOT, structure="Interposed"
)
optimizer = SciPyOptimizer(method="COBYQA")
backend = QiliSim()
result = backend.execute(
VariationalProgram(
functional=DigitalPropagation(ansatz),
optimizer=optimizer,
cost_function=ModelCostFunction(model),
),
Readout().with_sampling(nshots=1000),
)
print(result)
Salida
VariationalProgramResult(
Optimal Cost=-9.0,
Optimal Parameters=[...],
Intermediate Results=[...],
Optimal Results=- Functional Results: [
Sampling Results: (
nshots=1000,
samples={'000': 2, '010': 3, '101': 994, '110': 1}
)
]
)
Ejemplo de Uso 2 (con el Backend QiliSim) Este ejemplo optimiza un schedule variacional bajo ciertas restricciones de parámetros.
from qilisdk.core.variables import LT, GreaterThan
from qilisdk.cost_functions.observable_cost_function import ObservableCostFunction
from qilisdk.functionals import VariationalProgram, AnalogEvolution
from qilisdk.optimizers.scipy_optimizer import SciPyOptimizer
from qilisdk.analog import *
from qilisdk.analog.schedule import Interpolation
from qilisdk.core.variables import Parameter
from qilisdk.core import ket, tensor_prod
from qilisdk.backends import QiliSim
from qilisdk.readout import Readout
import numpy as np
from qilisdk.utils.visualization.style import ScheduleStyle
T = 10
p = [Parameter(f"p_{i}", (i + 1)*2, bounds=(0, 10)) for i in range(4)]
p.insert(0, 0)
p.append(T)
s = [Parameter(f"s_{i}", (i + 2) * 0.1, bounds=(0, 1)) for i in range(2)]
h0 = X(0)
h1 = Z(0)
max_time = Parameter("max_time", 1.5)
schedule = Schedule(
hamiltonians={"h_x": h0, "h_z": h1},
coefficients={
"h_x": {p[0]: 1, (p[1], p[2]): 1 - s[0], (p[3], p[4]): 1 - s[1], p[5]: 0},
"h_z": {p[0]: 0, (p[1], p[2]): s[0], (p[3], p[4]): s[1], p[5]: 1},
},
interpolation=Interpolation.LINEAR,
)
schedule.draw(ScheduleStyle(title="Schedule Before Optimization"))
te = AnalogEvolution(
schedule=schedule,
initial_state=tensor_prod([ket(0) - ket(1) for _ in range(schedule.nqubits)]).unit(),
)
vp = VariationalProgram(
te,
SciPyOptimizer(method="COBYQA"),
cost_function=ObservableCostFunction(h1),
parameter_constraints=[
GreaterThan(p[3], 5)
]
)
print(vp.get_constraints()) # print the constraints of the variational program.
backend = QiliSim()
results = backend.execute(vp, Readout().with_expectation(observables=[h1]).with_state_tomography().with_sampling(nshots=1000))
schedule.draw(ScheduleStyle(title="Schedule After Optimization"))
print(results)