Source code for qailab.qlauncher.passes.backward
1""" Backward pass algorithm implementation in quantum_launcher. """
2from collections.abc import Callable
3from typing import Any, Literal
4from quantum_launcher.base.base import Backend, Problem, Result
5from quantum_launcher.routines.qiskit_routines import QiskitBackend
6from qailab.qlauncher.passes.forward import ForwardPass
7from qailab.gradient.gradient_calculation import calculate_jacobian
8
9
[docs]
10class BackwardPass(ForwardPass):
11 """ Backward Pass, calculates two jacobian matrices: w.r.t. to input and w.r.t. weights"""
12
13 def __init__(self, gradient_method: Literal['param_shift', 'spsa', 'lin_comb'] = 'param_shift', shots: int = 1024) -> None:
14 self.gradient_method = gradient_method
15 self.shots = shots
16 super().__init__()
17
[docs]
18 def run(self, problem: Problem, backend: Backend, formatter: Callable[..., Any] | None = None) -> Result:
19 if formatter is None:
20 raise ValueError('Formatter for Backward pass not found!')
21 if not isinstance(backend, QiskitBackend):
22 raise ValueError('Wrong sampler given into')
23
24 format_result = formatter(problem)[0]
25 if not isinstance(format_result, tuple):
26 raise ValueError("Don't use autobind")
27
28 circuit, params = format_result
29
30 input_params = {x: params[x] for x in params if x.name.startswith('input')}
31 weight_params = {x: params[x] for x in params if x.name.startswith('weight')}
32
33 # All other params must be assigned.
34 input_jacobian = calculate_jacobian(
35 circuit.assign_parameters(weight_params),
36 input_params,
37 backend,
38 self.gradient_method,
39 self.shots
40 )
41 weight_jacobian = calculate_jacobian(
42 circuit.assign_parameters(input_params),
43 weight_params,
44 backend,
45 self.gradient_method,
46 self.shots
47 )
48
49 return Result('', 0, '', 0, {}, {}, self.shots, 0, 0, {'input': input_jacobian, 'weight': weight_jacobian})