diff --git a/qsvm.py b/qsvm.py new file mode 100644 index 0000000..2d7d5d2 --- /dev/null +++ b/qsvm.py @@ -0,0 +1,436 @@ +import numpy as np +import pandas as pd +import os +import sys +import time +from datetime import datetime +import json +import gc +import signal +import multiprocessing +from multiprocessing import Pool + +# Import bibliotek kwantowych +from qiskit import Aer +from qiskit.circuit.library import ZZFeatureMap, PauliFeatureMap, EfficientSU2 +from qiskit_machine_learning.kernels import QuantumKernel +from qiskit_machine_learning.algorithms import QSVC +import dimod + +# Dodanie zalecanego zamiennika dla ZZFeatureMap +from qiskit.circuit import QuantumCircuit, Parameter +from qiskit.circuit.library.data_preparation import ZFeatureMap + +# Dodanie bibliotek do kodowania amplitudowego +from qiskit.circuit import QuantumCircuit +from qiskit.extensions import Initialize +import scipy.linalg as la + +# Dodanie biblioteki UMAP +import umap + +# Maksymalny czas trwania eksperymentu +MAX_EXECUTION_TIME = 24 * 60 * 60 * 7 * 3 + +def timeout_handler(signum, frame): + print("\n\n======= PRZEKROCZONO MAKSYMALNY CZAS WYKONANIA =======") + print(f"Eksperyment został przerwany po {MAX_EXECUTION_TIME/3600:.1f} godzinach.") + sys.exit(1) + +# Ustawienie obsługi sygnału +signal.signal(signal.SIGALRM, timeout_handler) +signal.alarm(MAX_EXECUTION_TIME) + +# ----------------- CZĘŚĆ 0: PARAMETRY KONFIGURACYJNE ----------------- + +# Parametry danych +DATA_FILES = [ + 'dane/TCGA_GBM_LGG_Mutations_all.csv', + 'dane/zaszumione_rozszerzone/TCGA_GBM_LGG_Mutations_noise_1percent_added.csv', + 'dane/zaszumione_rozszerzone/TCGA_GBM_LGG_Mutations_noise_5percent_added.csv', + 'dane/zaszumione_rozszerzone/TCGA_GBM_LGG_Mutations_noise_10percent_added.csv', + 'dane/zaszumione_rozszerzone/TCGA_GBM_LGG_Mutations_noise_15percent_added.csv', + 'dane/zaszumione_rozszerzone/TCGA_GBM_LGG_Mutations_noise_20percent_added.csv', + 'dane/zaszumione/TCGA_GBM_LGG_Mutations_noise_1percent_substituted.csv', + 'dane/zaszumione/TCGA_GBM_LGG_Mutations_noise_5percent_substituted.csv', + 'dane/zaszumione/TCGA_GBM_LGG_Mutations_noise_10percent_substituted.csv', + 'dane/zaszumione/TCGA_GBM_LGG_Mutations_noise_15percent_substituted.csv', + 'dane/zaszumione/TCGA_GBM_LGG_Mutations_noise_20percent_substituted.csv' +] +TEST_SIZE = 0.3 +RANDOM_STATE = 42 + +# Parametry redukcji wymiarowości +USE_PCA = True +USE_TSNE = False +USE_UMAP = False +PCA_COMPONENTS = 14 +TSNE_COMPONENTS = 3 +TSNE_PERPLEXITY = 100 +TSNE_LEARNING_RATE = 50 +TSNE_MAX_ITER = 1000 +UMAP_COMPONENTS = 14 +UMAP_NEIGHBORS = 15 +UMAP_MIN_DIST = 0.8 +UMAP_METRIC = 'euclidean' +EVALUATE_SILHOUETTE = False +OPTIMAL_SILHOUETTE_SCORE = 0.1964 + +# Wybór eksperymentów do przeprowadzenia +RUN_CLASSIC_SVM = True +RUN_QUANTUM_SVM = True +RUN_HYBRID_APPROACH = True + +# Parametry klasycznego SVM +SVM_PARAM_GRID = { + 'C': [0.1, 1, 10, 100], + 'gamma': ['scale', 'auto', 0.1, 0.01], + 'kernel': ['linear', 'rbf', 'poly'] +} +SVM_CV = 5 + +# Parametry kwantowego SVM +BACKEND_NAME = 'qasm_simulator' +C_VALUES = [0.1, 1.0, 10.0] +QSVM_CV = 10 + +# Parametry wyżarzania kwantowego +NUM_READS = 100 +QUBO_PENALTY = 10.0 + +# Parametry analizy cech +IMPORTANCE_THRESHOLD = 0.01 + +# Parametry wyjściowe +OUTPUT_DIR = f'wyniki/2025-08-04-dim_reduction-{QSVM_CV}-fold' + +# Parametry IBM Quantum Cloud +USE_IBM_QUANTUM = False +IBM_BACKEND = 'qasm_simulator' +IBM_REAL_BACKEND = 'qasm_simulator' +IBM_TOKEN = None +IBM_INSTANCE = None +IBM_MAX_SHOTS = 1024 +IBM_OPTIMIZATION_LEVEL = 1 +IBM_RESILIENCE_LEVEL = 1 + +# Upewnij się, że katalog wyjściowy istnieje +if not os.path.exists(OUTPUT_DIR): + os.makedirs(OUTPUT_DIR) + +# Przekierowanie wyjścia do pliku i konsoli +class Logger: + def __init__(self, filename): + self.terminal = sys.stdout + self.log = open(filename, 'w', encoding='utf-8') + + def write(self, message): + self.terminal.write(message) + self.log.write(message) + self.log.flush() + + def flush(self): + self.terminal.flush() + self.log.flush() + + def close(self): + self.log.close() + +# Funkcja do zapisywania szczegółowych metryk +def save_metrics(y_true, y_pred, model_name): + from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score + + accuracy = accuracy_score(y_true, y_pred) + precision = precision_score(y_true, y_pred, average='weighted', zero_division=0) + recall = recall_score(y_true, y_pred, average='weighted', zero_division=0) + f1 = f1_score(y_true, y_pred, average='weighted', zero_division=0) + + try: + roc_auc = roc_auc_score(y_true, y_pred) + except: + roc_auc = "N/A" + + print(f"\nSzczegółowe metryki dla modelu {model_name}:") + print(f"Accuracy: {accuracy:.4f}") + print(f"Precision: {precision:.4f}") + print(f"Recall: {recall:.4f}") + print(f"F1 Score: {f1:.4f}") + print(f"ROC AUC: {roc_auc}") + + cm = confusion_matrix(y_true, y_pred) + print("\nMacierz pomyłek:") + print(cm) + + return { + 'accuracy': accuracy, + 'precision': precision, + 'recall': recall, + 'f1': f1, + 'roc_auc': roc_auc, + 'confusion_matrix': cm.tolist() + } + +# Funkcja do zapisywania wyników pośrednich +def save_results_cache(results_dict, cache_file): + with open(cache_file, 'w') as f: + json.dump(results_dict, f) + +# Funkcja do wczytywania wyników pośrednich +def load_results_cache(cache_file): + if os.path.exists(cache_file): + try: + with open(cache_file, 'r') as f: + return json.load(f) + except: + print("Nie udało się wczytać pliku cache. Tworzenie nowego.") + return { + 'quantum_results': [], + 'quantum_times': {}, + 'completed_feature_maps': [], + 'hybrid_scores': {}, + 'hybrid_eval_times': {} + } + +# Funkcja do inicjalizacji lokalnego symulatora +def initialize_ibm_quantum(): + print("\n======= INICJALIZACJA LOKALNEGO SYMULATORA =======") + print("IBM Quantum Cloud wyłączone - używanie lokalnego symulatora") + + try: + backend = Aer.get_backend('qasm_simulator') + print("✓ Zainicjalizowano lokalny symulator Qiskit Aer") + print(f"✓ Backend: {backend.name}") + + return None, backend, True + + except Exception as e: + print(f"BŁĄD podczas inicjalizacji lokalnego symulatora: {str(e)}") + return None, None, False + +# Funkcja do przygotowania danych +def prepare_data(data_file): + from sklearn.model_selection import train_test_split + from sklearn.preprocessing import StandardScaler + from sklearn.decomposition import PCA + from sklearn.manifold import TSNE + from sklearn.metrics import silhouette_score + + print(f"\n======= PRZYGOTOWANIE DANYCH =======") + start_time_data = time.time() + + # Wczytanie danych + data = pd.read_csv(data_file) + print(f"Wymiary oryginalnych danych: {data.shape}") + + # Wydzielenie zmiennej docelowej + y = data['Primary_Diagnosis'] + print(f"Unikalne wartości zmiennej docelowej: {y.unique()}") + print(f"Rozkład klas: {y.value_counts().to_dict()}") + + # Usunięcie kolumn identyfikacyjnych + id_columns = ['Project', 'Case_ID'] + data_processed = data.drop(id_columns + ['Grade'], axis=1) + print(f"Wymiary danych po usunięciu kolumn identyfikacyjnych: {data_processed.shape}") + + # Przekształcenie kolumn kategorycznych na binarne + print("Przekształcanie kolumn kategorycznych na binarne...") + categorical_columns = data_processed.select_dtypes(include=['object']).columns.tolist() + print(f"Kolumny kategoryczne do przekształcenia: {categorical_columns}") + + # Przekształcenie każdej kolumny kategorycznej + for col in categorical_columns: + unique_values = data_processed[col].unique() + print(f"Kolumna {col} zawiera wartości: {unique_values}") + + if len(unique_values) == 2: + if set(unique_values) == {'Yes', 'No'}: + data_processed[col] = data_processed[col].map({'Yes': 1, 'No': 0}) + elif set(unique_values) == {'Male', 'Female'}: + data_processed[col] = data_processed[col].map({'Male': 1, 'Female': 0}) + elif set(unique_values) == {'GBM', 'LGG'}: + data_processed[col] = data_processed[col].map({'GBM': 1, 'LGG': 0}) + else: + data_processed[col] = pd.factorize(data_processed[col])[0] + else: + try: + data_processed[col] = pd.to_numeric(data_processed[col], errors='raise') + print(f"Kolumna {col} została przekształcona na liczbową.") + except: + print(f"Kolumna {col} zostanie zakodowana jako one-hot.") + dummies = pd.get_dummies(data_processed[col], prefix=col, drop_first=True) + data_processed = pd.concat([data_processed, dummies], axis=1) + data_processed.drop(col, axis=1, inplace=True) + + # Sprawdzenie, czy wszystkie dane są numeryczne + non_numeric = data_processed.select_dtypes(include=['object']).columns.tolist() + if non_numeric: + print(f"UWAGA: Pozostały kolumny nieliczbowe: {non_numeric}") + print("Usuwanie pozostałych kolumn nieliczbowych...") + data_processed = data_processed.drop(non_numeric, axis=1) + + print(f"Wymiary danych po przekształceniu: {data_processed.shape}") + + # Wypełnienie brakujących wartości + if data_processed.isnull().sum().sum() > 0: + print("Wypełnianie brakujących wartości...") + data_processed.fillna(data_processed.mean(), inplace=True) + + # Przygotowanie danych do modelowania + X = data_processed.values + print(f"Wymiary danych wejściowych: {X.shape}") + + # Przetwarzanie cech + scaler = StandardScaler() + X_scaled = scaler.fit_transform(X) + print(f"Wymiary danych po skalowaniu: {X_scaled.shape}") + + # Redukcja wymiarowości + print("\n======= REDUKCJA WYMIAROWOŚCI =======") + + # Przygotowanie różnych wersji zredukowanych danych + X_reduced_versions = {} + + if USE_PCA: + pca_components = min(PCA_COMPONENTS, X_scaled.shape[1]) + print(f"Liczba komponentów PCA: {pca_components}") + pca = PCA(n_components=pca_components) + X_reduced_pca = pca.fit_transform(X_scaled) + print(f"Wymiary danych po redukcji PCA: {X_reduced_pca.shape}") + print(f"Wyjaśniona wariancja: {sum(pca.explained_variance_ratio_):.4f}") + X_reduced_versions['pca'] = X_reduced_pca + + if USE_TSNE: + print(f"\nStosowanie t-SNE na danych skalowanych...") + tsne = TSNE( + n_components=TSNE_COMPONENTS, + perplexity=TSNE_PERPLEXITY, + learning_rate=TSNE_LEARNING_RATE, + n_iter=TSNE_MAX_ITER, + random_state=RANDOM_STATE + ) + tsne_start_time = time.time() + X_reduced_tsne = tsne.fit_transform(X_scaled) + tsne_end_time = time.time() + tsne_time = tsne_end_time - tsne_start_time + print(f"Wymiary danych po redukcji t-SNE: {X_reduced_tsne.shape}") + print(f"Czas wykonania t-SNE: {tsne_time:.2f} sekund") + + if EVALUATE_SILHOUETTE: + try: + silhouette_avg = silhouette_score(X_reduced_tsne, y) + print(f"Silhouette Score dla t-SNE: {silhouette_avg:.4f}") + except Exception as e: + print(f"Nie udało się obliczyć Silhouette Score: {str(e)}") + + X_reduced_versions['tsne'] = X_reduced_tsne + + if USE_UMAP: + print(f"\nStosowanie UMAP na danych skalowanych...") + umap_reducer = umap.UMAP( + n_components=UMAP_COMPONENTS, + n_neighbors=UMAP_NEIGHBORS, + min_dist=UMAP_MIN_DIST, + metric=UMAP_METRIC, + random_state=RANDOM_STATE + ) + umap_start_time = time.time() + X_reduced_umap = umap_reducer.fit_transform(X_scaled) + umap_end_time = time.time() + umap_time = umap_end_time - umap_start_time + print(f"Wymiary danych po redukcji UMAP: {X_reduced_umap.shape}") + print(f"Czas wykonania UMAP: {umap_time:.2f} sekund") + + if EVALUATE_SILHOUETTE: + try: + silhouette_avg_umap = silhouette_score(X_reduced_umap, y) + print(f"Silhouette Score dla UMAP: {silhouette_avg_umap:.4f}") + except Exception as e: + print(f"Nie udało się obliczyć Silhouette Score dla UMAP: {str(e)}") + + X_reduced_versions['umap'] = X_reduced_umap + + # Wybór domyślnej wersji zredukowanych danych + if 'pca' in X_reduced_versions: + X_reduced = X_reduced_versions['pca'] + print("Używanie danych zredukowanych przez PCA jako domyślnych.") + elif 'umap' in X_reduced_versions: + X_reduced = X_reduced_versions['umap'] + print("Używanie danych zredukowanych przez UMAP jako domyślnych.") + elif 'tsne' in X_reduced_versions: + X_reduced = X_reduced_versions['tsne'] + print("Używanie danych zredukowanych przez t-SNE jako domyślnych.") + else: + X_reduced = X_scaled + print("Nie wybrano żadnej metody redukcji wymiarowości. Używanie oryginalnych danych skalowanych.") + + # Podział na zbiory treningowy i testowy + X_train_reduced, X_test_reduced, y_train, y_test = train_test_split( + X_reduced, y, test_size=TEST_SIZE, random_state=RANDOM_STATE + ) + + # Podział dla oryginalnych danych + X_train, X_test, _, _ = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE) + + print(f"Wymiary zbioru treningowego: {X_train_reduced.shape}") + print(f"Wymiary zbioru testowego: {X_test_reduced.shape}") + + end_time_data = time.time() + data_preparation_time = end_time_data - start_time_data + print(f"\nCzas przygotowania danych: {data_preparation_time:.2f} sekund") + + return { + 'X_train': X_train, + 'X_test': X_test, + 'X_train_reduced': X_train_reduced, + 'X_test_reduced': X_test_reduced, + 'y_train': y_train, + 'y_test': y_test, + 'data_processed': data_processed, + 'preparation_time': data_preparation_time + } + +def run_experiment_parallel(exp_file): + """Uruchom pojedynczy eksperyment""" + if exp_file == 'qsvm1_zz.py': + import qsvm1_zz + return qsvm1_zz.run_experiment() + elif exp_file == 'qsvm2_pauli.py': + import qsvm2_pauli + return qsvm2_pauli.run_experiment() + elif exp_file == 'qsvm3_z.py': + import qsvm3_z + return qsvm3_z.run_experiment() + elif exp_file == 'qsvm4_amplitude.py': + import qsvm4_amplitude + return qsvm4_amplitude.run_experiment() + elif exp_file == 'qsvm5_hybrid.py': + import qsvm5_hybrid + return qsvm5_hybrid.run_experiment() + else: + print(f"Nieznany eksperyment: {exp_file}") + return None + +def run_all_experiments_parallel(): + """Uruchom wszystkie eksperymenty równolegle""" + experiment_files = [ + 'qsvm1_zz.py', + 'qsvm2_pauli.py', + 'qsvm3_z.py', + 'qsvm4_amplitude.py', + 'qsvm5_hybrid.py' + ] + + # Użyj 5 procesów (jeden na eksperyment) + with Pool(5) as p: + results = p.map(run_experiment_parallel, experiment_files) + + return results + +if __name__ == "__main__": + print("======= KONTROLER EKSPERYMENTÓW QSVM =======") + print(f"CPU cores: {multiprocessing.cpu_count()}") + print(f"Uruchamianie 5 eksperymentów równolegle...") + + results = run_all_experiments_parallel() + + print("======= WSZYSTKIE EKSPERYMENTY ZAKOŃCZONE =======") \ No newline at end of file diff --git a/qsvm1_zz.py b/qsvm1_zz.py new file mode 100644 index 0000000..7729276 --- /dev/null +++ b/qsvm1_zz.py @@ -0,0 +1,316 @@ +import numpy as np +import pandas as pd +import os +import sys +import time +from datetime import datetime +from sklearn.svm import SVC +from sklearn.model_selection import GridSearchCV, train_test_split, KFold +from sklearn.preprocessing import StandardScaler +from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score +from sklearn.inspection import permutation_importance +from sklearn.decomposition import PCA +import json +import gc + +# Import bibliotek kwantowych +from qiskit import Aer +from qiskit.circuit.library import ZZFeatureMap +from qiskit_machine_learning.kernels import QuantumKernel +from qiskit_machine_learning.algorithms import QSVC + +# Import funkcji z głównego modułu +import qsvm + +def run_experiment(): + """ + Eksperyment 1: ZZ1 i ZZ2 Feature Maps + Testuje klasyczny SVM i kwantowy SVM z mapami cech ZZ1 i ZZ2 + """ + + print("======= EKSPERYMENT 1: ZZ1 i ZZ2 FEATURE MAPS =======") + + # Konfiguracja eksperymentu + FEATURE_MAPS = { + 'ZZ1': {'reps': 1, 'enabled': True}, + 'ZZ2': {'reps': 2, 'enabled': True} + } + + # Dla każdego pliku danych + for data_file in qsvm.DATA_FILES: + if not os.path.exists(data_file): + print(f"Pominięto {data_file} - plik nie istnieje") + continue + + print(f"\n======= PRZETWARZANIE PLIKU: {data_file} =======") + + # Utwórz nazwę pliku wyjściowego + file_base_name = os.path.basename(data_file).split('.')[0] + output_file = os.path.join(qsvm.OUTPUT_DIR, f'wyniki_zz_{file_base_name}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.txt') + + # Utwórz plik cache + cache_file = os.path.join(qsvm.OUTPUT_DIR, f'qsvm_zz_cache_{file_base_name}.json') + + # Przekierowanie wyjścia + logger = qsvm.Logger(output_file) + sys.stdout = logger + + try: + # Przygotowanie danych + data_dict = qsvm.prepare_data(data_file) + X_train = data_dict['X_train'] + X_test = data_dict['X_test'] + X_train_reduced = data_dict['X_train_reduced'] + X_test_reduced = data_dict['X_test_reduced'] + y_train = data_dict['y_train'] + y_test = data_dict['y_test'] + data_processed = data_dict['data_processed'] + + # Inicjalizacja backendu + ibm_service, ibm_backend, ibm_success = qsvm.initialize_ibm_quantum() + + # ----------------- KLASYCZNY SVM ----------------- + if qsvm.RUN_CLASSIC_SVM: + print("\n======= KLASYCZNY SVM (BASELINE) =======") + start_time_classic = time.time() + + # Trenowanie modelu + grid = GridSearchCV(SVC(), qsvm.SVM_PARAM_GRID, cv=qsvm.SVM_CV, scoring='accuracy') + grid.fit(X_train, y_train) + print("Najlepsze parametry klasycznego SVM:", grid.best_params_) + print("Dokładność klasycznego SVM:", grid.best_score_) + + # Ewaluacja modelu + classic_pred = grid.predict(X_test) + print("Raport klasyfikacji (klasyczny SVM):") + print(classification_report(y_test, classic_pred, zero_division=0)) + + # Zapisz szczegółowe metryki + classic_metrics = qsvm.save_metrics(y_test, classic_pred, "Klasyczny SVM") + + end_time_classic = time.time() + classic_svm_time = end_time_classic - start_time_classic + print(f"\nCzas trenowania i ewaluacji klasycznego SVM: {classic_svm_time:.2f} sekund") + else: + print("\n======= KLASYCZNY SVM (BASELINE) - POMINIĘTY =======") + classic_svm_time = 0 + classic_metrics = None + + # ----------------- KWANTOWY SVM ----------------- + if qsvm.RUN_QUANTUM_SVM: + print("\n======= KWANTOWY SVM Z ZZ FEATURE MAPS =======") + start_time_quantum = time.time() + + # Wczytaj cache + cache = qsvm.load_results_cache(cache_file) + quantum_results = cache.get('quantum_results', []) + + # Tworzenie map cech + feature_maps = [] + feature_dimension = X_train_reduced.shape[1] + + for name, config in FEATURE_MAPS.items(): + if config['enabled']: + feature_map = ZZFeatureMap(feature_dimension=feature_dimension, reps=config['reps']) + feature_maps.append({'name': name, 'map': feature_map}) + + print(f"Testowanie {len(feature_maps)} map cech: {[fm['name'] for fm in feature_maps]}") + + # Testowanie każdej mapy cech + for fm in feature_maps: + for C in qsvm.C_VALUES: + # Sprawdź cache + already_tested = False + for name, c_val, _ in quantum_results: + if name == fm['name'] and c_val == C: + already_tested = True + break + + if already_tested: + print(f"Pomijanie już przetestowanej kombinacji: {fm['name']}, C={C}") + continue + + fm_start_time = time.time() + + try: + print(f"Testowanie {fm['name']} z C={C}...") + + # Debugowanie danych + print(f" Wymiary danych: X_train_reduced {X_train_reduced.shape}") + print(f" Sprawdzenie NaN: {np.isnan(X_train_reduced).sum()}") + print(f" Sprawdzenie inf: {np.isinf(X_train_reduced).sum()}") + print(f" Zakres danych: [{X_train_reduced.min():.4f}, {X_train_reduced.max():.4f}]") + + # Utworzenie quantum kernel z debugowaniem + quantum_kernel = QuantumKernel( + feature_map=fm['map'], + quantum_instance=ibm_backend + ) + + # Test quantum kernel + print(f" Testowanie quantum kernel...") + try: + test_kernel = quantum_kernel.evaluate(X_train_reduced[:2], X_train_reduced[:2]) + print(f" Test kernel shape: {test_kernel.shape}") + print(f" Test kernel range: [{test_kernel.min():.4f}, {test_kernel.max():.4f}]") + if np.isnan(test_kernel).any() or np.isinf(test_kernel).any(): + print(f" BŁĄD: Kernel zawiera NaN lub inf!") + continue + except Exception as e: + print(f" BŁĄD testowania kernel: {str(e)}") + continue + + # Utworzenie SVM z niestandardowym jądrem i debugowaniem + def custom_kernel(X, Y): + try: + kernel_matrix = quantum_kernel.evaluate(X, Y) + # Sprawdź czy kernel jest poprawny + if np.isnan(kernel_matrix).any() or np.isinf(kernel_matrix).any(): + print(f" BŁĄD: Kernel matrix zawiera NaN lub inf!") + return np.eye(len(X), len(Y)) # Fallback + return kernel_matrix + except Exception as e: + print(f" BŁĄD kernel evaluation: {str(e)}") + return np.eye(len(X), len(Y)) # Fallback + + qsvm_model = SVC(kernel=custom_kernel, C=C, random_state=qsvm.RANDOM_STATE) + + # Walidacja krzyżowa z debugowaniem + cv_start_time = time.time() + scores = [] + + kf = KFold(n_splits=qsvm.QSVM_CV, shuffle=True, random_state=qsvm.RANDOM_STATE) + + for fold, (train_idx, val_idx) in enumerate(kf.split(X_train_reduced)): + X_cv_train, X_cv_val = X_train_reduced[train_idx], X_train_reduced[val_idx] + y_cv_train, y_cv_val = y_train.iloc[train_idx], y_train.iloc[val_idx] + + print(f" Fold {fold+1}/{qsvm.QSVM_CV}: train {X_cv_train.shape}, val {X_cv_val.shape}") + + try: + qsvm_model.fit(X_cv_train, y_cv_train) + score = qsvm_model.score(X_cv_val, y_cv_val) + scores.append(score) + print(f" Fold {fold+1} score: {score:.4f}") + except Exception as e: + print(f" BŁĄD fold {fold+1}: {str(e)}") + scores.append(0.0) # Fallback + + if len(scores) > 0: + mean_score = np.mean(scores) + std_score = np.std(scores) + print(f" Wszystkie scores: {scores}") + print(f" Mean score: {mean_score:.4f} ± {std_score:.4f}") + else: + mean_score = 0.0 + print(f" BŁĄD: Brak poprawnych scores!") + + cv_end_time = time.time() + cv_time = cv_end_time - cv_start_time + + quantum_results.append((fm['name'], C, mean_score)) + + fm_end_time = time.time() + fm_time = fm_end_time - fm_start_time + + print(f"Dokładność kwantowego SVM z {fm['name']}, C={C}: {mean_score:.4f} (czas: {fm_time:.2f} s)") + + # Zapisz wyniki pośrednie + cache['quantum_results'] = quantum_results + qsvm.save_results_cache(cache, cache_file) + + except Exception as e: + print(f"BŁĄD dla {fm['name']}, C={C}: {str(e)}") + # Dodaj fallback wynik + quantum_results.append((fm['name'], C, 0.0)) + cache['quantum_results'] = quantum_results + qsvm.save_results_cache(cache, cache_file) + continue + + # Znajdź najlepszy model kwantowy + if quantum_results: + best_qsvm = max(quantum_results, key=lambda x: x[2]) + print(f"\nNajlepszy kwantowy SVM: {best_qsvm[0]} z C={best_qsvm[1]}, dokładność: {best_qsvm[2]:.4f}") + + # Ewaluacja najlepszego modelu + best_feature_map = None + for fm in feature_maps: + if fm['name'] == best_qsvm[0]: + best_feature_map = fm['map'] + break + + if best_feature_map: + quantum_kernel_best = QuantumKernel( + feature_map=best_feature_map, + quantum_instance=ibm_backend + ) + + qsvm_best = SVC(kernel=quantum_kernel_best.evaluate, C=best_qsvm[1]) + qsvm_best.fit(X_train_reduced, y_train) + + quantum_pred = qsvm_best.predict(X_test_reduced) + print("Raport klasyfikacji (najlepszy kwantowy SVM):") + print(classification_report(y_test, quantum_pred, zero_division=0)) + + quantum_metrics = qsvm.save_metrics(y_test, quantum_pred, f"Kwantowy SVM {best_qsvm[0]}") + else: + print("Nie udało się wytrenować żadnego modelu kwantowego.") + quantum_metrics = None + + end_time_quantum = time.time() + quantum_svm_time = end_time_quantum - start_time_quantum + print(f"\nCałkowity czas dla kwantowego SVM: {quantum_svm_time:.2f} sekund") + else: + print("\n======= KWANTOWY SVM - POMINIĘTY =======") + quantum_svm_time = 0 + quantum_metrics = None + + # ----------------- ANALIZA WYNIKÓW ----------------- + print("\n======= PORÓWNANIE WYNIKÓW =======") + if classic_metrics: + print(f"Klasyczny SVM: {classic_metrics['accuracy']:.4f}") + if quantum_metrics: + print(f"Kwantowy SVM: {quantum_metrics['accuracy']:.4f}") + + # Analiza znaczenia cech (tylko dla klasycznego SVM) + if qsvm.RUN_CLASSIC_SVM and classic_metrics: + print("\n======= ANALIZA ZNACZENIA CECH =======") + importance_start_time = time.time() + + result = permutation_importance(grid.best_estimator_, X_test, y_test, n_repeats=10, random_state=qsvm.RANDOM_STATE) + important_features = [] + + feature_columns = list(data_processed.columns) + + for i in range(len(feature_columns)): + if result.importances_mean[i] > qsvm.IMPORTANCE_THRESHOLD: + important_features.append((feature_columns[i], result.importances_mean[i])) + + print("Najważniejsze cechy dla klasyfikacji:") + for feature, importance in sorted(important_features, key=lambda x: x[1], reverse=True): + print(f" {feature}: {importance:.4f}") + + importance_end_time = time.time() + importance_time = importance_end_time - importance_start_time + print(f"\nCzas analizy znaczenia cech: {importance_time:.2f} sekund") + + # Podsumowanie + print("\n======= PODSUMOWANIE EKSPERYMENTU ZZ =======") + print(f"Data i czas zakończenia: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + total_time = time.time() - data_dict['preparation_time'] + print(f"Całkowity czas eksperymentu: {total_time:.2f} sekund") + + except Exception as e: + print(f"BŁĄD podczas przetwarzania {data_file}: {str(e)}") + finally: + # Zamknięcie pliku wyjściowego + logger.close() + sys.stdout = logger.terminal + + # Czyszczenie pamięci + gc.collect() + + print("\n======= EKSPERYMENT 1 ZAKOŃCZONY =======") + +if __name__ == "__main__": + run_experiment() \ No newline at end of file diff --git a/qsvm2_pauli.py b/qsvm2_pauli.py new file mode 100644 index 0000000..46e6a46 --- /dev/null +++ b/qsvm2_pauli.py @@ -0,0 +1,316 @@ +import numpy as np +import pandas as pd +import os +import sys +import time +from datetime import datetime +from sklearn.svm import SVC +from sklearn.model_selection import GridSearchCV, train_test_split, KFold +from sklearn.preprocessing import StandardScaler +from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score +from sklearn.inspection import permutation_importance +from sklearn.decomposition import PCA +import json +import gc + +# Import bibliotek kwantowych +from qiskit import Aer +from qiskit.circuit.library import PauliFeatureMap +from qiskit_machine_learning.kernels import QuantumKernel +from qiskit_machine_learning.algorithms import QSVC + +# Import funkcji z głównego modułu +import qsvm + +def run_experiment(): + """ + Eksperyment 2: Pauli1 i Pauli2 Feature Maps + Testuje klasyczny SVM i kwantowy SVM z mapami cech Pauli1 i Pauli2 + """ + + print("======= EKSPERYMENT 2: PAULI1 i PAULI2 FEATURE MAPS =======") + + # Konfiguracja eksperymentu + FEATURE_MAPS = { + 'Pauli1': {'reps': 1, 'enabled': True}, + 'Pauli2': {'reps': 2, 'enabled': True} + } + + # Dla każdego pliku danych + for data_file in qsvm.DATA_FILES: + if not os.path.exists(data_file): + print(f"Pominięto {data_file} - plik nie istnieje") + continue + + print(f"\n======= PRZETWARZANIE PLIKU: {data_file} =======") + + # Utwórz nazwę pliku wyjściowego + file_base_name = os.path.basename(data_file).split('.')[0] + output_file = os.path.join(qsvm.OUTPUT_DIR, f'wyniki_pauli_{file_base_name}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.txt') + + # Utwórz plik cache + cache_file = os.path.join(qsvm.OUTPUT_DIR, f'qsvm_pauli_cache_{file_base_name}.json') + + # Przekierowanie wyjścia + logger = qsvm.Logger(output_file) + sys.stdout = logger + + try: + # Przygotowanie danych + data_dict = qsvm.prepare_data(data_file) + X_train = data_dict['X_train'] + X_test = data_dict['X_test'] + X_train_reduced = data_dict['X_train_reduced'] + X_test_reduced = data_dict['X_test_reduced'] + y_train = data_dict['y_train'] + y_test = data_dict['y_test'] + data_processed = data_dict['data_processed'] + + # Inicjalizacja backendu + ibm_service, ibm_backend, ibm_success = qsvm.initialize_ibm_quantum() + + # ----------------- KLASYCZNY SVM ----------------- + if qsvm.RUN_CLASSIC_SVM: + print("\n======= KLASYCZNY SVM (BASELINE) =======") + start_time_classic = time.time() + + # Trenowanie modelu + grid = GridSearchCV(SVC(), qsvm.SVM_PARAM_GRID, cv=qsvm.SVM_CV, scoring='accuracy') + grid.fit(X_train, y_train) + print("Najlepsze parametry klasycznego SVM:", grid.best_params_) + print("Dokładność klasycznego SVM:", grid.best_score_) + + # Ewaluacja modelu + classic_pred = grid.predict(X_test) + print("Raport klasyfikacji (klasyczny SVM):") + print(classification_report(y_test, classic_pred, zero_division=0)) + + # Zapisz szczegółowe metryki + classic_metrics = qsvm.save_metrics(y_test, classic_pred, "Klasyczny SVM") + + end_time_classic = time.time() + classic_svm_time = end_time_classic - start_time_classic + print(f"\nCzas trenowania i ewaluacji klasycznego SVM: {classic_svm_time:.2f} sekund") + else: + print("\n======= KLASYCZNY SVM (BASELINE) - POMINIĘTY =======") + classic_svm_time = 0 + classic_metrics = None + + # ----------------- KWANTOWY SVM ----------------- + if qsvm.RUN_QUANTUM_SVM: + print("\n======= KWANTOWY SVM Z PAULI FEATURE MAPS =======") + start_time_quantum = time.time() + + # Wczytaj cache + cache = qsvm.load_results_cache(cache_file) + quantum_results = cache.get('quantum_results', []) + + # Tworzenie map cech + feature_maps = [] + feature_dimension = X_train_reduced.shape[1] + + for name, config in FEATURE_MAPS.items(): + if config['enabled']: + feature_map = PauliFeatureMap(feature_dimension=feature_dimension, reps=config['reps']) + feature_maps.append({'name': name, 'map': feature_map}) + + print(f"Testowanie {len(feature_maps)} map cech: {[fm['name'] for fm in feature_maps]}") + + # Testowanie każdej mapy cech + for fm in feature_maps: + for C in qsvm.C_VALUES: + # Sprawdź cache + already_tested = False + for name, c_val, _ in quantum_results: + if name == fm['name'] and c_val == C: + already_tested = True + break + + if already_tested: + print(f"Pomijanie już przetestowanej kombinacji: {fm['name']}, C={C}") + continue + + fm_start_time = time.time() + + try: + print(f"Testowanie {fm['name']} z C={C}...") + + # Debugowanie danych + print(f" Wymiary danych: X_train_reduced {X_train_reduced.shape}") + print(f" Sprawdzenie NaN: {np.isnan(X_train_reduced).sum()}") + print(f" Sprawdzenie inf: {np.isinf(X_train_reduced).sum()}") + print(f" Zakres danych: [{X_train_reduced.min():.4f}, {X_train_reduced.max():.4f}]") + + # Utworzenie quantum kernel z debugowaniem + quantum_kernel = QuantumKernel( + feature_map=fm['map'], + quantum_instance=ibm_backend + ) + + # Test quantum kernel + print(f" Testowanie quantum kernel...") + try: + test_kernel = quantum_kernel.evaluate(X_train_reduced[:2], X_train_reduced[:2]) + print(f" Test kernel shape: {test_kernel.shape}") + print(f" Test kernel range: [{test_kernel.min():.4f}, {test_kernel.max():.4f}]") + if np.isnan(test_kernel).any() or np.isinf(test_kernel).any(): + print(f" BŁĄD: Kernel zawiera NaN lub inf!") + continue + except Exception as e: + print(f" BŁĄD testowania kernel: {str(e)}") + continue + + # Utworzenie SVM z niestandardowym jądrem i debugowaniem + def custom_kernel(X, Y): + try: + kernel_matrix = quantum_kernel.evaluate(X, Y) + # Sprawdź czy kernel jest poprawny + if np.isnan(kernel_matrix).any() or np.isinf(kernel_matrix).any(): + print(f" BŁĄD: Kernel matrix zawiera NaN lub inf!") + return np.eye(len(X), len(Y)) # Fallback + return kernel_matrix + except Exception as e: + print(f" BŁĄD kernel evaluation: {str(e)}") + return np.eye(len(X), len(Y)) # Fallback + + qsvm_model = SVC(kernel=custom_kernel, C=C, random_state=qsvm.RANDOM_STATE) + + # Walidacja krzyżowa z debugowaniem + cv_start_time = time.time() + scores = [] + + kf = KFold(n_splits=qsvm.QSVM_CV, shuffle=True, random_state=qsvm.RANDOM_STATE) + + for fold, (train_idx, val_idx) in enumerate(kf.split(X_train_reduced)): + X_cv_train, X_cv_val = X_train_reduced[train_idx], X_train_reduced[val_idx] + y_cv_train, y_cv_val = y_train.iloc[train_idx], y_train.iloc[val_idx] + + print(f" Fold {fold+1}/{qsvm.QSVM_CV}: train {X_cv_train.shape}, val {X_cv_val.shape}") + + try: + qsvm_model.fit(X_cv_train, y_cv_train) + score = qsvm_model.score(X_cv_val, y_cv_val) + scores.append(score) + print(f" Fold {fold+1} score: {score:.4f}") + except Exception as e: + print(f" BŁĄD fold {fold+1}: {str(e)}") + scores.append(0.0) # Fallback + + if len(scores) > 0: + mean_score = np.mean(scores) + std_score = np.std(scores) + print(f" Wszystkie scores: {scores}") + print(f" Mean score: {mean_score:.4f} ± {std_score:.4f}") + else: + mean_score = 0.0 + print(f" BŁĄD: Brak poprawnych scores!") + + cv_end_time = time.time() + cv_time = cv_end_time - cv_start_time + + quantum_results.append((fm['name'], C, mean_score)) + + fm_end_time = time.time() + fm_time = fm_end_time - fm_start_time + + print(f"Dokładność kwantowego SVM z {fm['name']}, C={C}: {mean_score:.4f} (czas: {fm_time:.2f} s)") + + # Zapisz wyniki pośrednie + cache['quantum_results'] = quantum_results + qsvm.save_results_cache(cache, cache_file) + + except Exception as e: + print(f"BŁĄD dla {fm['name']}, C={C}: {str(e)}") + # Dodaj fallback wynik + quantum_results.append((fm['name'], C, 0.0)) + cache['quantum_results'] = quantum_results + qsvm.save_results_cache(cache, cache_file) + continue + + # Znajdź najlepszy model kwantowy + if quantum_results: + best_qsvm = max(quantum_results, key=lambda x: x[2]) + print(f"\nNajlepszy kwantowy SVM: {best_qsvm[0]} z C={best_qsvm[1]}, dokładność: {best_qsvm[2]:.4f}") + + # Ewaluacja najlepszego modelu + best_feature_map = None + for fm in feature_maps: + if fm['name'] == best_qsvm[0]: + best_feature_map = fm['map'] + break + + if best_feature_map: + quantum_kernel_best = QuantumKernel( + feature_map=best_feature_map, + quantum_instance=ibm_backend + ) + + qsvm_best = SVC(kernel=quantum_kernel_best.evaluate, C=best_qsvm[1]) + qsvm_best.fit(X_train_reduced, y_train) + + quantum_pred = qsvm_best.predict(X_test_reduced) + print("Raport klasyfikacji (najlepszy kwantowy SVM):") + print(classification_report(y_test, quantum_pred, zero_division=0)) + + quantum_metrics = qsvm.save_metrics(y_test, quantum_pred, f"Kwantowy SVM {best_qsvm[0]}") + else: + print("Nie udało się wytrenować żadnego modelu kwantowego.") + quantum_metrics = None + + end_time_quantum = time.time() + quantum_svm_time = end_time_quantum - start_time_quantum + print(f"\nCałkowity czas dla kwantowego SVM: {quantum_svm_time:.2f} sekund") + else: + print("\n======= KWANTOWY SVM - POMINIĘTY =======") + quantum_svm_time = 0 + quantum_metrics = None + + # ----------------- ANALIZA WYNIKÓW ----------------- + print("\n======= PORÓWNANIE WYNIKÓW =======") + if classic_metrics: + print(f"Klasyczny SVM: {classic_metrics['accuracy']:.4f}") + if quantum_metrics: + print(f"Kwantowy SVM: {quantum_metrics['accuracy']:.4f}") + + # Analiza znaczenia cech (tylko dla klasycznego SVM) + if qsvm.RUN_CLASSIC_SVM and classic_metrics: + print("\n======= ANALIZA ZNACZENIA CECH =======") + importance_start_time = time.time() + + result = permutation_importance(grid.best_estimator_, X_test, y_test, n_repeats=10, random_state=qsvm.RANDOM_STATE) + important_features = [] + + feature_columns = list(data_processed.columns) + + for i in range(len(feature_columns)): + if result.importances_mean[i] > qsvm.IMPORTANCE_THRESHOLD: + important_features.append((feature_columns[i], result.importances_mean[i])) + + print("Najważniejsze cechy dla klasyfikacji:") + for feature, importance in sorted(important_features, key=lambda x: x[1], reverse=True): + print(f" {feature}: {importance:.4f}") + + importance_end_time = time.time() + importance_time = importance_end_time - importance_start_time + print(f"\nCzas analizy znaczenia cech: {importance_time:.2f} sekund") + + # Podsumowanie + print("\n======= PODSUMOWANIE EKSPERYMENTU PAULI =======") + print(f"Data i czas zakończenia: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + total_time = time.time() - data_dict['preparation_time'] + print(f"Całkowity czas eksperymentu: {total_time:.2f} sekund") + + except Exception as e: + print(f"BŁĄD podczas przetwarzania {data_file}: {str(e)}") + finally: + # Zamknięcie pliku wyjściowego + logger.close() + sys.stdout = logger.terminal + + # Czyszczenie pamięci + gc.collect() + + print("\n======= EKSPERYMENT 2 ZAKOŃCZONY =======") + +if __name__ == "__main__": + run_experiment() \ No newline at end of file diff --git a/qsvm3_z.py b/qsvm3_z.py new file mode 100644 index 0000000..0177b3e --- /dev/null +++ b/qsvm3_z.py @@ -0,0 +1,269 @@ +import numpy as np +import pandas as pd +import os +import sys +import time +from datetime import datetime +from sklearn.svm import SVC +from sklearn.model_selection import GridSearchCV, train_test_split, KFold +from sklearn.preprocessing import StandardScaler +from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score +from sklearn.inspection import permutation_importance +from sklearn.decomposition import PCA +import json +import gc + +# Import bibliotek kwantowych +from qiskit import Aer +from qiskit.circuit.library.data_preparation import ZFeatureMap +from qiskit_machine_learning.kernels import QuantumKernel +from qiskit_machine_learning.algorithms import QSVC + +# Import funkcji z głównego modułu +import qsvm + +def run_experiment(): + """ + Eksperyment 3: Z1 i Z2 Feature Maps + Testuje klasyczny SVM i kwantowy SVM z mapami cech Z1 i Z2 + """ + + print("======= EKSPERYMENT 3: Z1 i Z2 FEATURE MAPS =======") + + # Konfiguracja eksperymentu + FEATURE_MAPS = { + 'Z1': {'reps': 1, 'enabled': True}, + 'Z2': {'reps': 2, 'enabled': True} + } + + # Dla każdego pliku danych + for data_file in qsvm.DATA_FILES: + if not os.path.exists(data_file): + print(f"Pominięto {data_file} - plik nie istnieje") + continue + + print(f"\n======= PRZETWARZANIE PLIKU: {data_file} =======") + + # Utwórz nazwę pliku wyjściowego + file_base_name = os.path.basename(data_file).split('.')[0] + output_file = os.path.join(qsvm.OUTPUT_DIR, f'wyniki_z_{file_base_name}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.txt') + + # Utwórz plik cache + cache_file = os.path.join(qsvm.OUTPUT_DIR, f'qsvm_z_cache_{file_base_name}.json') + + # Przekierowanie wyjścia + logger = qsvm.Logger(output_file) + sys.stdout = logger + + try: + # Przygotowanie danych + data_dict = qsvm.prepare_data(data_file) + X_train = data_dict['X_train'] + X_test = data_dict['X_test'] + X_train_reduced = data_dict['X_train_reduced'] + X_test_reduced = data_dict['X_test_reduced'] + y_train = data_dict['y_train'] + y_test = data_dict['y_test'] + data_processed = data_dict['data_processed'] + + # Inicjalizacja backendu + ibm_service, ibm_backend, ibm_success = qsvm.initialize_ibm_quantum() + + # ----------------- KLASYCZNY SVM ----------------- + if qsvm.RUN_CLASSIC_SVM: + print("\n======= KLASYCZNY SVM (BASELINE) =======") + start_time_classic = time.time() + + # Trenowanie modelu + grid = GridSearchCV(SVC(), qsvm.SVM_PARAM_GRID, cv=qsvm.SVM_CV, scoring='accuracy') + grid.fit(X_train, y_train) + print("Najlepsze parametry klasycznego SVM:", grid.best_params_) + print("Dokładność klasycznego SVM:", grid.best_score_) + + # Ewaluacja modelu + classic_pred = grid.predict(X_test) + print("Raport klasyfikacji (klasyczny SVM):") + print(classification_report(y_test, classic_pred, zero_division=0)) + + # Zapisz szczegółowe metryki + classic_metrics = qsvm.save_metrics(y_test, classic_pred, "Klasyczny SVM") + + end_time_classic = time.time() + classic_svm_time = end_time_classic - start_time_classic + print(f"\nCzas trenowania i ewaluacji klasycznego SVM: {classic_svm_time:.2f} sekund") + else: + print("\n======= KLASYCZNY SVM (BASELINE) - POMINIĘTY =======") + classic_svm_time = 0 + classic_metrics = None + + # ----------------- KWANTOWY SVM ----------------- + if qsvm.RUN_QUANTUM_SVM: + print("\n======= KWANTOWY SVM Z Z FEATURE MAPS =======") + start_time_quantum = time.time() + + # Wczytaj cache + cache = qsvm.load_results_cache(cache_file) + quantum_results = cache.get('quantum_results', []) + + # Tworzenie map cech + feature_maps = [] + feature_dimension = X_train_reduced.shape[1] + + for name, config in FEATURE_MAPS.items(): + if config['enabled']: + feature_map = ZFeatureMap(feature_dimension=feature_dimension, reps=config['reps']) + feature_maps.append({'name': name, 'map': feature_map}) + + print(f"Testowanie {len(feature_maps)} map cech: {[fm['name'] for fm in feature_maps]}") + + # Testowanie każdej mapy cech + for fm in feature_maps: + for C in qsvm.C_VALUES: + # Sprawdź cache + already_tested = False + for name, c_val, _ in quantum_results: + if name == fm['name'] and c_val == C: + already_tested = True + break + + if already_tested: + print(f"Pomijanie już przetestowanej kombinacji: {fm['name']}, C={C}") + continue + + fm_start_time = time.time() + + try: + print(f"Testowanie {fm['name']} z C={C}...") + + # Utworzenie quantum kernel + quantum_kernel = QuantumKernel( + feature_map=fm['map'], + quantum_instance=ibm_backend + ) + + # Utworzenie SVM z niestandardowym jądrem + def custom_kernel(X, Y): + return quantum_kernel.evaluate(X, Y) + + qsvm_model = SVC(kernel=custom_kernel, C=C) + + # Walidacja krzyżowa + cv_start_time = time.time() + scores = [] + + kf = KFold(n_splits=qsvm.QSVM_CV, shuffle=True, random_state=qsvm.RANDOM_STATE) + + for train_idx, val_idx in kf.split(X_train_reduced): + X_cv_train, X_cv_val = X_train_reduced[train_idx], X_train_reduced[val_idx] + y_cv_train, y_cv_val = y_train.iloc[train_idx], y_train.iloc[val_idx] + + qsvm_model.fit(X_cv_train, y_cv_train) + score = qsvm_model.score(X_cv_val, y_cv_val) + scores.append(score) + + mean_score = np.mean(scores) + cv_end_time = time.time() + cv_time = cv_end_time - cv_start_time + + quantum_results.append((fm['name'], C, mean_score)) + + fm_end_time = time.time() + fm_time = fm_end_time - fm_start_time + + print(f"Dokładność kwantowego SVM z {fm['name']}, C={C}: {mean_score:.4f} (czas: {fm_time:.2f} s)") + + # Zapisz wyniki pośrednie + cache['quantum_results'] = quantum_results + qsvm.save_results_cache(cache, cache_file) + + except Exception as e: + print(f"Błąd dla {fm['name']}, C={C}: {str(e)}") + continue + + # Znajdź najlepszy model kwantowy + if quantum_results: + best_qsvm = max(quantum_results, key=lambda x: x[2]) + print(f"\nNajlepszy kwantowy SVM: {best_qsvm[0]} z C={best_qsvm[1]}, dokładność: {best_qsvm[2]:.4f}") + + # Ewaluacja najlepszego modelu + best_feature_map = None + for fm in feature_maps: + if fm['name'] == best_qsvm[0]: + best_feature_map = fm['map'] + break + + if best_feature_map: + quantum_kernel_best = QuantumKernel( + feature_map=best_feature_map, + quantum_instance=ibm_backend + ) + + qsvm_best = SVC(kernel=quantum_kernel_best.evaluate, C=best_qsvm[1]) + qsvm_best.fit(X_train_reduced, y_train) + + quantum_pred = qsvm_best.predict(X_test_reduced) + print("Raport klasyfikacji (najlepszy kwantowy SVM):") + print(classification_report(y_test, quantum_pred, zero_division=0)) + + quantum_metrics = qsvm.save_metrics(y_test, quantum_pred, f"Kwantowy SVM {best_qsvm[0]}") + else: + print("Nie udało się wytrenować żadnego modelu kwantowego.") + quantum_metrics = None + + end_time_quantum = time.time() + quantum_svm_time = end_time_quantum - start_time_quantum + print(f"\nCałkowity czas dla kwantowego SVM: {quantum_svm_time:.2f} sekund") + else: + print("\n======= KWANTOWY SVM - POMINIĘTY =======") + quantum_svm_time = 0 + quantum_metrics = None + + # ----------------- ANALIZA WYNIKÓW ----------------- + print("\n======= PORÓWNANIE WYNIKÓW =======") + if classic_metrics: + print(f"Klasyczny SVM: {classic_metrics['accuracy']:.4f}") + if quantum_metrics: + print(f"Kwantowy SVM: {quantum_metrics['accuracy']:.4f}") + + # Analiza znaczenia cech (tylko dla klasycznego SVM) + if qsvm.RUN_CLASSIC_SVM and classic_metrics: + print("\n======= ANALIZA ZNACZENIA CECH =======") + importance_start_time = time.time() + + result = permutation_importance(grid.best_estimator_, X_test, y_test, n_repeats=10, random_state=qsvm.RANDOM_STATE) + important_features = [] + + feature_columns = list(data_processed.columns) + + for i in range(len(feature_columns)): + if result.importances_mean[i] > qsvm.IMPORTANCE_THRESHOLD: + important_features.append((feature_columns[i], result.importances_mean[i])) + + print("Najważniejsze cechy dla klasyfikacji:") + for feature, importance in sorted(important_features, key=lambda x: x[1], reverse=True): + print(f" {feature}: {importance:.4f}") + + importance_end_time = time.time() + importance_time = importance_end_time - importance_start_time + print(f"\nCzas analizy znaczenia cech: {importance_time:.2f} sekund") + + # Podsumowanie + print("\n======= PODSUMOWANIE EKSPERYMENTU Z =======") + print(f"Data i czas zakończenia: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + total_time = time.time() - data_dict['preparation_time'] + print(f"Całkowity czas eksperymentu: {total_time:.2f} sekund") + + except Exception as e: + print(f"BŁĄD podczas przetwarzania {data_file}: {str(e)}") + finally: + # Zamknięcie pliku wyjściowego + logger.close() + sys.stdout = logger.terminal + + # Czyszczenie pamięci + gc.collect() + + print("\n======= EKSPERYMENT 3 ZAKOŃCZONY =======") + +if __name__ == "__main__": + run_experiment() \ No newline at end of file diff --git a/qsvm4_amplitude.py b/qsvm4_amplitude.py new file mode 100644 index 0000000..50fab21 --- /dev/null +++ b/qsvm4_amplitude.py @@ -0,0 +1,331 @@ +import numpy as np +import pandas as pd +import os +import sys +import time +from datetime import datetime +from sklearn.svm import SVC +from sklearn.model_selection import GridSearchCV, train_test_split, KFold +from sklearn.preprocessing import StandardScaler +from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score, accuracy_score, precision_score, recall_score, f1_score +from sklearn.inspection import permutation_importance +from sklearn.decomposition import PCA +import json +import gc + +# Import bibliotek kwantowych +from qiskit import Aer +from qiskit.circuit.library import ZZFeatureMap +from qiskit_machine_learning.kernels import QuantumKernel +from qiskit_machine_learning.algorithms import QSVC + +# Import funkcji z głównego modułu +import qsvm + +# Funkcja do przygotowania danych dla kodowania amplitudowego +def prepare_data_for_amplitude_encoding(data, normalization='l2'): + """ + Przygotowuje dane dla kodowania amplitudowego z różnymi normalizacjami. + + Args: + data: Dane wejściowe + normalization: Typ normalizacji ('l2', 'l1', 'min-max') + + Returns: + Przygotowane dane + """ + if normalization == 'l2': + # Normalizacja L2 + norms = np.linalg.norm(data, axis=1, ord=2) + norms[norms == 0] = 1.0 + return data / norms[:, np.newaxis] + elif normalization == 'l1': + # Normalizacja L1 + norms = np.linalg.norm(data, axis=1, ord=1) + norms[norms == 0] = 1.0 + return data / norms[:, np.newaxis] + elif normalization == 'min-max': + # Normalizacja min-max + min_vals = np.min(data, axis=1, keepdims=True) + max_vals = np.max(data, axis=1, keepdims=True) + range_vals = max_vals - min_vals + range_vals[range_vals == 0] = 1.0 + return (data - min_vals) / range_vals + else: + raise ValueError(f"Nieznana normalizacja: {normalization}") + +# Funkcja jądra amplitudowego +def amplitude_kernel(x1, x2): + """ + Oblicza jądro amplitudowe między dwoma wektorami. + + Args: + x1, x2: Wektory wejściowe + + Returns: + Wartość jądra amplitudowego + """ + # Oblicz iloczyn skalarny + dot_product = np.dot(x1, x2) + + # Jądro amplitudowe to kwadrat iloczynu skalarnego + return dot_product ** 2 + +# Klasa jądra amplitudowego +class AmplitudeKernel: + def __init__(self, feature_dimension, normalization='l2'): + self.feature_dimension = feature_dimension + self.normalization = normalization + + def evaluate(self, x1_vec, x2_vec): + """Oblicza macierz jądra amplitudowego""" + # Przygotowanie danych + x1_prepared = prepare_data_for_amplitude_encoding(x1_vec, self.normalization) + x2_prepared = prepare_data_for_amplitude_encoding(x2_vec, self.normalization) + + # Obliczanie macierzy jądra + kernel_matrix = np.zeros((x1_prepared.shape[0], x2_prepared.shape[0])) + for i in range(x1_prepared.shape[0]): + for j in range(x2_prepared.shape[0]): + kernel_matrix[i, j] = amplitude_kernel(x1_prepared[i], x2_prepared[j]) + + return kernel_matrix + +def run_experiment(): + """ + Eksperyment 4: Amplitude Encoding + Testuje klasyczny SVM i kwantowy SVM z kodowaniem amplitudowym + """ + + print("======= EKSPERYMENT 4: AMPLITUDE ENCODING =======") + + # Konfiguracja eksperymentu + AMPLITUDE_NORMALIZATIONS = ['l2', 'l1', 'min-max'] + + # Dla każdego pliku danych + for data_file in qsvm.DATA_FILES: + if not os.path.exists(data_file): + print(f"Pominięto {data_file} - plik nie istnieje") + continue + + print(f"\n======= PRZETWARZANIE PLIKU: {data_file} =======") + + # Utwórz nazwę pliku wyjściowego + file_base_name = os.path.basename(data_file).split('.')[0] + output_file = os.path.join(qsvm.OUTPUT_DIR, f'wyniki_amplitude_{file_base_name}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.txt') + + # Utwórz plik cache + cache_file = os.path.join(qsvm.OUTPUT_DIR, f'qsvm_amplitude_cache_{file_base_name}.json') + + # Przekierowanie wyjścia + logger = qsvm.Logger(output_file) + sys.stdout = logger + + try: + # Przygotowanie danych + data_dict = qsvm.prepare_data(data_file) + X_train = data_dict['X_train'] + X_test = data_dict['X_test'] + X_train_reduced = data_dict['X_train_reduced'] + X_test_reduced = data_dict['X_test_reduced'] + y_train = data_dict['y_train'] + y_test = data_dict['y_test'] + data_processed = data_dict['data_processed'] + + # Inicjalizacja backendu + ibm_service, ibm_backend, ibm_success = qsvm.initialize_ibm_quantum() + + # ----------------- KLASYCZNY SVM ----------------- + if qsvm.RUN_CLASSIC_SVM: + print("\n======= KLASYCZNY SVM (BASELINE) =======") + start_time_classic = time.time() + + # Trenowanie modelu + grid = GridSearchCV(SVC(), qsvm.SVM_PARAM_GRID, cv=qsvm.SVM_CV, scoring='accuracy') + grid.fit(X_train, y_train) + print("Najlepsze parametry klasycznego SVM:", grid.best_params_) + print("Dokładność klasycznego SVM:", grid.best_score_) + + # Ewaluacja modelu + classic_pred = grid.predict(X_test) + print("Raport klasyfikacji (klasyczny SVM):") + print(classification_report(y_test, classic_pred, zero_division=0)) + + # Zapisz szczegółowe metryki + classic_metrics = qsvm.save_metrics(y_test, classic_pred, "Klasyczny SVM") + + end_time_classic = time.time() + classic_svm_time = end_time_classic - start_time_classic + print(f"\nCzas trenowania i ewaluacji klasycznego SVM: {classic_svm_time:.2f} sekund") + else: + print("\n======= KLASYCZNY SVM (BASELINE) - POMINIĘTY =======") + classic_svm_time = 0 + classic_metrics = None + + # ----------------- KWANTOWY SVM Z AMPLITUDE ENCODING ----------------- + if qsvm.RUN_QUANTUM_SVM: + print("\n======= KWANTOWY SVM Z AMPLITUDE ENCODING =======") + start_time_quantum = time.time() + + # Wczytaj cache + cache = qsvm.load_results_cache(cache_file) + quantum_results = cache.get('quantum_results', []) + + # Testowanie każdej normalizacji + for normalization in AMPLITUDE_NORMALIZATIONS: + feature_map_name = f'Amplitude_{normalization}' + + for C in qsvm.C_VALUES: + # Sprawdź cache + already_tested = False + for name, c_val, _ in quantum_results: + if name == feature_map_name and c_val == C: + already_tested = True + break + + if already_tested: + print(f"Pomijanie już przetestowanej kombinacji: {feature_map_name}, C={C}") + continue + + fm_start_time = time.time() + + try: + print(f"Testowanie {feature_map_name} z C={C}...") + + # Utworzenie jądra amplitudowego + amplitude_kernel_obj = AmplitudeKernel( + feature_dimension=X_train_reduced.shape[1], + normalization=normalization + ) + + # Utworzenie SVM z niestandardowym jądrem + def custom_kernel(X, Y): + return amplitude_kernel_obj.evaluate(X, Y) + + qsvm_model = SVC(kernel=custom_kernel, C=C) + + # Walidacja krzyżowa + cv_start_time = time.time() + scores = [] + + kf = KFold(n_splits=qsvm.QSVM_CV, shuffle=True, random_state=qsvm.RANDOM_STATE) + + for train_idx, val_idx in kf.split(X_train_reduced): + X_cv_train, X_cv_val = X_train_reduced[train_idx], X_train_reduced[val_idx] + y_cv_train, y_cv_val = y_train.iloc[train_idx], y_train.iloc[val_idx] + + qsvm_model.fit(X_cv_train, y_cv_train) + score = qsvm_model.score(X_cv_val, y_cv_val) + scores.append(score) + + mean_score = np.mean(scores) + cv_end_time = time.time() + cv_time = cv_end_time - cv_start_time + + quantum_results.append((feature_map_name, C, mean_score)) + + fm_end_time = time.time() + fm_time = fm_end_time - fm_start_time + + print(f"Dokładność kwantowego SVM z {feature_map_name}, C={C}: {mean_score:.4f} (czas: {fm_time:.2f} s)") + + # Zapisz wyniki pośrednie + cache['quantum_results'] = quantum_results + qsvm.save_results_cache(cache, cache_file) + + except Exception as e: + print(f"Błąd dla {feature_map_name}, C={C}: {str(e)}") + continue + + # Znajdź najlepszy model kwantowy + if quantum_results: + best_qsvm = max(quantum_results, key=lambda x: x[2]) + print(f"\nNajlepszy kwantowy SVM: {best_qsvm[0]} z C={best_qsvm[1]}, dokładność: {best_qsvm[2]:.4f}") + + # Ewaluacja najlepszego modelu + best_normalization = best_qsvm[0].split('_')[1] + print(f"Ewaluacja najlepszego modelu z kodowaniem amplitudowym (normalizacja: {best_normalization})...") + + # Utworzenie jądra kwantowego + amplitude_kernel_best = AmplitudeKernel( + feature_dimension=X_train_reduced.shape[1], + normalization=best_normalization + ) + + # Utworzenie klasyfikatora SVC z niestandardowym jądrem + def custom_kernel(X, Y): + return amplitude_kernel_best.evaluate(X, Y) + + qsvm_best = SVC(kernel=custom_kernel, C=best_qsvm[1]) + + # Trenowanie modelu + qsvm_best.fit(X_train_reduced, y_train) + + # Ewaluacja modelu + quantum_pred = qsvm_best.predict(X_test_reduced) + print(f"Raport klasyfikacji (najlepszy kwantowy SVM z kodowaniem amplitudowym, normalizacja: {best_normalization}):") + print(classification_report(y_test, quantum_pred, zero_division=0)) + + # Zapisz szczegółowe metryki + quantum_metrics = qsvm.save_metrics(y_test, quantum_pred, f"Kwantowy SVM z kodowaniem amplitudowym ({best_normalization})") + else: + print("Nie udało się wytrenować żadnego modelu kwantowego.") + quantum_metrics = None + + end_time_quantum = time.time() + quantum_svm_time = end_time_quantum - start_time_quantum + print(f"\nCałkowity czas dla kwantowego SVM: {quantum_svm_time:.2f} sekund") + else: + print("\n======= KWANTOWY SVM - POMINIĘTY =======") + quantum_svm_time = 0 + quantum_metrics = None + + # ----------------- ANALIZA WYNIKÓW ----------------- + print("\n======= PORÓWNANIE WYNIKÓW =======") + if classic_metrics: + print(f"Klasyczny SVM: {classic_metrics['accuracy']:.4f}") + if quantum_metrics: + print(f"Kwantowy SVM: {quantum_metrics['accuracy']:.4f}") + + # Analiza znaczenia cech (tylko dla klasycznego SVM) + if qsvm.RUN_CLASSIC_SVM and classic_metrics: + print("\n======= ANALIZA ZNACZENIA CECH =======") + importance_start_time = time.time() + + result = permutation_importance(grid.best_estimator_, X_test, y_test, n_repeats=10, random_state=qsvm.RANDOM_STATE) + important_features = [] + + feature_columns = list(data_processed.columns) + + for i in range(len(feature_columns)): + if result.importances_mean[i] > qsvm.IMPORTANCE_THRESHOLD: + important_features.append((feature_columns[i], result.importances_mean[i])) + + print("Najważniejsze cechy dla klasyfikacji:") + for feature, importance in sorted(important_features, key=lambda x: x[1], reverse=True): + print(f" {feature}: {importance:.4f}") + + importance_end_time = time.time() + importance_time = importance_end_time - importance_start_time + print(f"\nCzas analizy znaczenia cech: {importance_time:.2f} sekund") + + # Podsumowanie + print("\n======= PODSUMOWANIE EKSPERYMENTU AMPLITUDE =======") + print(f"Data i czas zakończenia: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + total_time = time.time() - data_dict['preparation_time'] + print(f"Całkowity czas eksperymentu: {total_time:.2f} sekund") + + except Exception as e: + print(f"BŁĄD podczas przetwarzania {data_file}: {str(e)}") + finally: + # Zamknięcie pliku wyjściowego + logger.close() + sys.stdout = logger.terminal + + # Czyszczenie pamięci + gc.collect() + + print("\n======= EKSPERYMENT 4 ZAKOŃCZONY =======") + +if __name__ == "__main__": + run_experiment() \ No newline at end of file