Source code for qlauncher.problems.optimization.qatm

  1from pathlib import Path
  2from typing import Literal
  3
  4import numpy as np
  5import pandas as pd
  6from qiskit import QuantumCircuit
  7
  8from qlauncher import hampy, models
  9from qlauncher.base.base import Problem
 10from qlauncher.hampy.object import Equation
 11from qlauncher.problems.optimization.ec import ring_ham
 12
 13
[docs] 14class QATM(Problem): 15 def __init__( 16 self, 17 cm: np.ndarray, 18 aircrafts: pd.DataFrame, 19 onehot: Literal['exact', 'quadratic', 'xor'] = 'exact', 20 optimization: bool = True, 21 ) -> None: 22 self.cm = cm 23 self.aircrafts = aircrafts 24 self.onehot = onehot 25 self.optimization = optimization 26 27 self.size = len(self.cm) 28
[docs] 29 @staticmethod 30 def from_preset(instance_name: Literal['rcp-3'], **kwargs) -> 'QATM': 31 match instance_name: 32 case 'rcp-3': 33 cm = np.array( 34 [ 35 [1, 0, 1, 0, 0, 0], 36 [0, 1, 0, 0, 0, 1], 37 [1, 0, 1, 0, 1, 0], 38 [0, 0, 0, 1, 0, 0], 39 [0, 0, 1, 0, 1, 0], 40 [0, 1, 0, 0, 0, 1], 41 ] 42 ) 43 aircrafts = pd.DataFrame( 44 { 45 'manouver': ['A0', 'A1', 'A2', 'A0_a=10', 'A1_a=10', 'A2_a=10'], 46 'aircraft': ['A0', 'A1', 'A2', 'A0', 'A1', 'A2'], 47 } 48 ) 49 case _: 50 raise KeyError 51 return QATM(cm, aircrafts)
52
[docs] 53 @classmethod 54 def from_file(cls, path: str, instance_name: str = 'QATM', optimization: bool = True) -> 'QATM': 55 cm_path = Path(path, 'CM_' + instance_name) 56 aircrafts_path = Path(path, 'aircrafts_' + instance_name) 57 58 return QATM( 59 np.loadtxt(cm_path), 60 pd.read_csv(aircrafts_path, delimiter=' ', names=['manouver', 'aircraft']), 61 'exact', 62 optimization, 63 )
64
[docs] 65 def to_hamiltonian(self, onehot: Literal['exact', 'quadratic', 'xor'] = 'exact') -> models.Hamiltonian: 66 cm = self.cm 67 aircrafts = self.aircrafts 68 size = len(cm) 69 70 onehot_hamiltonian = Equation(size) 71 for _, manouvers in aircrafts.groupby(by='aircraft'): 72 if onehot == 'exact': 73 h = ~hampy.one_in_n(manouvers.index.values.tolist(), size) 74 elif onehot == 'quadratic': 75 h = hampy.one_in_n(manouvers.index.values.tolist(), size, quadratic=True) 76 elif onehot == 'xor': 77 total = Equation(size) 78 for part in manouvers.index.values.tolist(): 79 total ^= total[part] 80 h = (~total).hamiltonian 81 82 onehot_hamiltonian += h 83 84 triu = np.triu(cm, k=1) 85 conflict_hamiltonian = Equation(size) 86 for p1, p2 in zip(*np.where(triu == 1), strict=True): 87 eq = Equation(size) 88 conflict_hamiltonian += (eq[int(p1)] & eq[int(p2)]).hamiltonian 89 90 hamiltonian = onehot_hamiltonian + conflict_hamiltonian 91 92 if self.optimization: 93 goal_hamiltonian = Equation(size) 94 for i, (maneuver, ac) in self.aircrafts.iterrows(): 95 if not isinstance(i, int): 96 raise TypeError 97 if maneuver != ac: 98 goal_hamiltonian += goal_hamiltonian.get_variable(i) 99 hamiltonian += goal_hamiltonian / cm.sum().sum() 100 101 return models.Hamiltonian( 102 hamiltonian, 103 mixer_hamiltonian=self.get_mixer_hamiltonian(), 104 initial_state=self.get_initial_state(), 105 )
106
[docs] 107 def get_mixer_hamiltonian(self) -> Equation: 108 mixer_hamiltonian = Equation(self.size) 109 for _, manouvers in self.aircrafts.groupby(by='aircraft'): 110 h = ring_ham(manouvers.index.values.tolist(), self.size) 111 mixer_hamiltonian += h 112 return mixer_hamiltonian
113
[docs] 114 def get_initial_state(self) -> QuantumCircuit: 115 qc = QuantumCircuit(self.size) 116 for _, manouvers in self.aircrafts.groupby(by='aircraft'): 117 qc.x(manouvers.index.values.tolist()[0]) 118 return qc
119
[docs] 120 def analyze_result(self, result: dict) -> dict[str, np.ndarray]: 121 """ 122 Analyzes the result in terms of collisions and violations of onehot constraint. 123 124 Parameters: 125 result (dict): A dictionary where keys are bitstrings and values are probabilities. 126 127 Returns: 128 dict: A dictionary containing collisions, onehot violations, and changes as ndarrays. 129 """ 130 keys = list(result.keys()) 131 vectorized_result = np.fromstring(' '.join(list(''.join(keys))), 'u1', sep=' ').reshape(len(result), -1) 132 cm = self.cm.copy().astype(int) 133 np.fill_diagonal(cm, 0) 134 collisions = np.einsum('ij,ij->i', vectorized_result @ cm, vectorized_result) / 2 135 136 df = pd.DataFrame(vectorized_result.transpose()) 137 df['aircraft'] = self.aircrafts['aircraft'] 138 onehot_violations = (df.groupby(by='aircraft').sum() != 1).sum(axis=0).to_numpy() 139 140 df['manouver'] = self.aircrafts['manouver'] 141 no_changes = df[df['aircraft'] == df['manouver']] 142 changes = (len(no_changes) - no_changes.drop(['manouver', 'aircraft'], axis=1).sum()).to_numpy().astype(int) 143 changes[onehot_violations != 0] = -1 144 145 at_least_one = (df.loc[:, df.columns != 'manouver'].groupby('aircraft').sum() > 0).all().to_numpy().astype(int) 146 147 return {'collisions': collisions, 'onehot_violations': onehot_violations, 'changes': changes, 'at_least_one': at_least_one}