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 = False, 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', onehot: Literal['exact', 'quadratic', 'xor'] = 'exact', optimization: bool = False) -> '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 onehot, 62 optimization, 63 )
64
[docs] 65 def to_hamiltonian(self, onehot: Literal['exact', 'quadratic', 'xor'] = None) -> models.Hamiltonian: 66 if onehot is None: 67 onehot = self.onehot 68 cm = self.cm 69 aircrafts = self.aircrafts 70 size = len(cm) 71 72 onehot_hamiltonian = Equation(size) 73 for _, manouvers in aircrafts.groupby(by='aircraft'): 74 if onehot == 'exact': 75 h = ~hampy.one_in_n(manouvers.index.values.tolist(), size) 76 elif onehot == 'quadratic': 77 h = hampy.one_in_n(manouvers.index.values.tolist(), size, quadratic=True) 78 elif onehot == 'xor': 79 total = Equation(size) 80 for part in manouvers.index.values.tolist(): 81 total ^= total[part] 82 h = (~total).hamiltonian 83 84 onehot_hamiltonian += h 85 86 triu = np.triu(cm, k=1) 87 conflict_hamiltonian = Equation(size) 88 for p1, p2 in zip(*np.where(triu == 1), strict=True): 89 eq = Equation(size) 90 conflict_hamiltonian += (eq[int(p1)] & eq[int(p2)]).hamiltonian 91 92 hamiltonian = onehot_hamiltonian + conflict_hamiltonian 93 94 if self.optimization: 95 goal_hamiltonian = Equation(size) 96 for i, (maneuver, ac) in self.aircrafts.iterrows(): 97 if not isinstance(i, int): 98 raise TypeError 99 if maneuver != ac: 100 goal_hamiltonian += goal_hamiltonian.get_variable(i) 101 hamiltonian += goal_hamiltonian / cm.sum().sum() 102 103 return models.Hamiltonian( 104 hamiltonian, 105 mixer_hamiltonian=self.get_mixer_hamiltonian(), 106 initial_state=self.get_initial_state(), 107 )
108
[docs] 109 def get_mixer_hamiltonian(self) -> Equation: 110 mixer_hamiltonian = Equation(self.size) 111 for _, manouvers in self.aircrafts.groupby(by='aircraft'): 112 h = ring_ham(manouvers.index.values.tolist(), self.size) 113 mixer_hamiltonian += h 114 return mixer_hamiltonian
115
[docs] 116 def get_initial_state(self) -> QuantumCircuit: 117 qc = QuantumCircuit(self.size) 118 for _, manouvers in self.aircrafts.groupby(by='aircraft'): 119 qc.x(manouvers.index.values.tolist()[0]) 120 return qc
121
[docs] 122 def analyze_result(self, result: dict) -> dict[str, np.ndarray]: 123 """ 124 Analyzes the result in terms of collisions and violations of onehot constraint. 125 126 Parameters: 127 result (dict): A dictionary where keys are bitstrings and values are probabilities. 128 129 Returns: 130 dict: A dictionary containing collisions, onehot violations, and changes as ndarrays. 131 """ 132 keys = list(result.keys()) 133 vectorized_result = np.fromstring(' '.join(list(''.join(keys))), 'u1', sep=' ').reshape(len(result), -1) 134 cm = self.cm.copy().astype(int) 135 np.fill_diagonal(cm, 0) 136 collisions = np.einsum('ij,ij->i', vectorized_result @ cm, vectorized_result) / 2 137 138 df = pd.DataFrame(vectorized_result.transpose()) 139 df['aircraft'] = self.aircrafts['aircraft'] 140 onehot_violations = (df.groupby(by='aircraft').sum() != 1).sum(axis=0).to_numpy() 141 142 df['manouver'] = self.aircrafts['manouver'] 143 no_changes = df[df['aircraft'] == df['manouver']] 144 changes = (len(no_changes) - no_changes.drop(['manouver', 'aircraft'], axis=1).sum()).to_numpy().astype(int) 145 changes[onehot_violations != 0] = -1 146 147 at_least_one = (df.loc[:, df.columns != 'manouver'].groupby('aircraft').sum() > 0).all().to_numpy().astype(int) 148 149 return {'collisions': collisions, 'onehot_violations': onehot_violations, 'changes': changes, 'at_least_one': at_least_one}