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[ComparisonTerm], 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.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)

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