Source code for qlauncher.routines.qiskit.algorithms.qml

  1from collections.abc import Sequence
  2
  3import numpy as np
  4from qiskit.circuit import Parameter, QuantumCircuit
  5from qiskit.primitives import BaseSampler, BaseSamplerV1, BaseSamplerV2
  6from qiskit.providers import Options
  7from qiskit.transpiler.passmanager import PassManager
  8from qiskit_machine_learning.kernels import FidelityQuantumKernel, TrainableFidelityQuantumKernel
  9from qiskit_machine_learning.kernels.algorithms import QuantumKernelTrainer
 10from qiskit_machine_learning.state_fidelities import BaseStateFidelity, ComputeUncompute
 11
 12from qlauncher.base.base import Algorithm, Result
 13from qlauncher.problems.other.tabular_ml import TabularML
 14from qlauncher.routines.qiskit.backends.gate_circuit_backend import GateCircuitBackend
 15
 16
[docs] 17class ComputeUncomputeCustom(ComputeUncompute): 18 """ 19 This is just :class:`qiskit_machine_learning.state_fidelities.ComputeUncompute` that checks 20 if a sampler is an instance of BaseSamplerV1 instead of BaseSampler. 21 The reason was that classes basing BaseSampler were getting isinstance(cls(),BaseSampler) == False 22 probably because of some qiskit shenanigans. 23 """ 24 25 def __init__( 26 self, 27 sampler: BaseSampler | BaseSamplerV2, 28 *, 29 options: Options | None = None, 30 local: bool = False, 31 pass_manager: PassManager | None = None, 32 ) -> None: 33 if (not isinstance(sampler, BaseSamplerV1)) and (not isinstance(sampler, BaseSamplerV2)): 34 raise ValueError(f'The sampler should be an instance of BaseSampler or BaseSamplerV2, but got {type(sampler)}') 35 self._sampler: BaseSamplerV1 | BaseSamplerV2 = sampler 36 self._pass_manager = pass_manager 37 self._local = local 38 self._default_options = Options() 39 if options is not None: 40 self._default_options.update_options(**options) 41 BaseStateFidelity.__init__(self) # pylint: disable=non-parent-init-called
42 43
[docs] 44class TrainQSVCKernel(Algorithm[TabularML, GateCircuitBackend]): 45 """ 46 Train a quantum kernel with additional parameters to be optimized. 47 The kernel will be optimized to provide maximum accuracy with a support vector classifier on the provided dataset. 48 If no trainable parameters are provided, the algorithm will return 49 a :class:`qiskit_machine_learning.kernels.FidelityQuantumKernel` kernel with a sampler assigned to the provided backend. 50 Otherwise an instance of :class:`qiskit_machine_learning.kernels.TrainableFidelityQuantumKernel` with optimal 51 parameters and a sampler assigned to the provided backend will be returned. 52 53 Args: 54 kernel_circuit(QuantumCircuit): A parametrizable quantum circuit. The measurements will be used to produce kernel output. 55 trainable_params(Sequence[Parameter] | None, optional): 56 The parameters to be optimized during training. If None no optimization will be done. Defaults to None. 57 """ 58 59 _algorithm_format = 'tabular_ml' 60 61 def __init__(self, kernel_circuit: QuantumCircuit, trainable_params: Sequence[Parameter] | None = None, **alg_kwargs) -> None: 62 super().__init__(**alg_kwargs) 63 self.kernel = kernel_circuit 64 self.trainable = trainable_params if trainable_params is not None else [] 65
[docs] 66 def run(self, problem: TabularML, backend: GateCircuitBackend) -> Result: 67 X = problem.X 68 y = problem.y 69 70 if not isinstance(X, np.ndarray): 71 raise ValueError(f'X is not of type np.ndarray: received {type(X)}') 72 73 if not isinstance(y, np.ndarray): 74 raise ValueError(f'y is not of type np.ndarray: received {type(y)}') 75 76 if isinstance(backend, GateCircuitBackend): 77 sampler = backend.samplerV1 78 else: 79 raise ValueError(f'The accepted backends are QiskitBackend and CirqBackend, got {type(backend)}') 80 81 if len(self.trainable) == 0: 82 return Result( 83 best_bitstring='', 84 best_energy=1, 85 most_common_bitstring='', 86 most_common_bitstring_energy=0, 87 distribution={}, 88 energies={}, 89 num_of_samples=0, 90 average_energy=0, 91 energy_std=0, 92 result=FidelityQuantumKernel(feature_map=self.kernel, fidelity=ComputeUncomputeCustom(sampler=sampler)), 93 ) 94 trainable_kernel = TrainableFidelityQuantumKernel( 95 feature_map=self.kernel, fidelity=ComputeUncomputeCustom(sampler=sampler), training_parameters=self.trainable 96 ) 97 kernel_trainer = QuantumKernelTrainer(trainable_kernel) 98 kernel_trainer.fit(X, y) 99 100 return Result( 101 best_bitstring='', 102 best_energy=1, 103 most_common_bitstring='', 104 most_common_bitstring_energy=0, 105 distribution={}, 106 energies={}, 107 num_of_samples=0, 108 average_energy=0, 109 energy_std=0, 110 result=kernel_trainer.quantum_kernel, 111 )