Programes variacionals

El funcional VariationalProgram reuneix les peces necessàries per a un algorisme quàntic variacional. Accepta un funcional primitiu parametritzat, un optimitzador i una funció de cost. Quan s’invoca execute(), avalua el funcional repetidament amb paràmetres actualitzats, introdueix el FunctionalResult resultant a la funció de cost subministrada i finalment retorna un VariationalProgramResult. Les restriccions de paràmetres (desigualtats/igualtats sobre paràmetres) s’adjunten a aquest nivell mitjançant l’argument parameter_constraints; aquest és el lloc per fer complir relacions com theta >= phi o límits entre paràmetres a tots els funcionals de QiliSDK. Només els paràmetres marcats com a entrenables s’optimitzen durant aquest bucle.

Paràmetres

  • functional (PrimitiveFunctional): Primitiu parametritzat a optimitzar (per exemple DigitalPropagation o AnalogEvolution).

  • optimizer (Optimizer): Optimitzador clàssic que proposa nous valors de paràmetres i opcionalment emmagatzema iterats intermedis.

  • cost_function (CostFunction): Objecte que mapeja els resultats funcionals a un cost escalar; freqüentment construït a partir d’un Model.

  • store_intermediate_results (bool, opcional): Quan és True, l’optimitzador conserva els passos intermedis, que s’exposen mitjançant intermediate_results.

  • parameter_constraints (list[Comparison], opcional): Restriccions sobre els paràmetres funcionals (p. ex., theta >= 0.5) avaluades abans de cada actualització de l’optimitzador. Aquest és el punt d’entrada admès per fer complir les relacions entre paràmetres a QiliSDK.

Retorna

Exemple d’ús (fent servir el backend QiliSim)

import numpy as np

from qilisdk.backends import QiliSim
from qilisdk.core.model import Model, ObjectiveSense
from qilisdk.core.comparison import LEQ
from qilisdk.core.variables import 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)

Sortida

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

]
)

Exemple d’ús 2 (fent servir el backend QiliSim) Aquest exemple optimitza un esquema variacional sota algunes restriccions de paràmetres.

from qilisdk.core.comparison 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)