PROTOCOLE OPÉRATIONNEL DE DÉTECTION DE TRACE SYSTÉMIQUE
Abstract
. PROTOCOLE OPÉRATIONNEL DE DÉTECTION DE TRACE SYSTÉMIQUE (Version finale – niveau instrumentation ) Auteur : Kevin FradierStatut : Instrument computationnelLicence : CC BY-NC-ND 4.0 1. Objet du protocole (formulation opératoire) Ce protocole permet de répondre sans interprétation à la question suivante : Un système donné présente-t-il une organisation interne non triviale, persistante et statistiquement robuste sous perturbation contrôlée ? La réponse produite est binaire + métrique, jamais explicative. 2. Entrée normalisée (contrainte dure) 2.1 Format requis Entrée : matrice carrée réelle M ∈ ℝⁿˣⁿ Contraintes : - n ≥ 10 - M symétrique - M normalisée (0 ≤ Mᵢⱼ ≤ 1 recommandé) Toute donnée pouvant être transformée en M est admissible.Le protocole ne dépend pas de l’origine des données. 3. Opérations exécutées (ordre fixe, non modifiable) Étape 1 — Extraction structurale Détection de motifs fermés de taille k ∈ [3, 6] Méthode : base de cycles non orientés Sortie : ensemble fini {C₁ … Cₘ} ⛔ Si m = 0 → arrêt immédiat (échec) Étape 2 — Mesure locale standardisée Pour chaque motif Cᵢ : sᵢ = trace(M[Cᵢ]) Aucune autre métrique autorisée Résultat : vecteur S = {s₁ … sₘ} Étape 3 — Agrégation globale I = mean(S) I est un indice, pas un invariant interprétatif. Étape 4 — Test de stabilité Ajout de bruit gaussien σ Répétitions : N ≥ 300 Calcul de I sous perturbation I_stable = mean(I₁ … Iₙ) Δ = |I - I_stable| Étape 5 — Robustesse statistique Bootstrap sur S IC à 95 % IC = [low, high] Étape 6 — Cartographie contributive Pour chaque élément j : contribution(j) = Σ (sᵢ / |Cᵢ|) pour tout Cᵢ contenant j Résultat : vecteur C ∈ ℝⁿ 4. Critères décisionnels (NON négociables) Le protocole retourne SUCCÈS si et seulement si : Critère Condition C1 Nombre de motifs m ≥ 5 C2 I ≠ 0 C3 Δ ≤ ε (ε typiquement 5–10 % de I) C4 IC n’inclut pas 0 C5 C n’est pas uniforme (test de variance > contrôle aléatoire) Sinon → ÉCHEC Aucune interprétation n’est attachée au succès. 5. Sortie standardisée (format labo) RESULT: - verdict: SUCCESS / FAILURE - motifs_count: m - invariant_index: I - stability_delta: Δ - confidence_interval: [low, high] - contribution_entropy: H(C) ➡️ Ce format est archivable, comparable, audit-able. 6. Contrôle négatif obligatoire Le même protocole doit être exécuté sur : matrice aléatoire de même dimension même distribution marginale Si le contrôle passe → protocole invalide. 7. Ce que le protocole GARANTIT (et seulement ça) ✔ Détection d’organisation locale non triviale✔ Persistance sous perturbation✔ Robustesse statistique✔ Comparabilité inter-systèmes 8. Ce que le protocole INTERDIT ❌ toute causalité❌ toute téléologie❌ toute cognition❌ toute “intelligence”❌ toute IA❌ toute explication Il mesure, point. 9👉 C’est un PROTOCOLE DE MESURE. Équivalent, en statut, à : un test de percolation un indice de complexité une mesure thermodynamique abstraite 👉 Python pur, dépendances standards (numpy, scipy, networkx)👉 Entrée = matrice👉 Sortie = verdict + métriques👉 Aucune interprétation CODE FINAL — PROTOCOLE DE DÉTECTION DE TRACE SYSTÉMIQUE import numpy as np import networkx as nx from itertools import combinations from scipy.stats import bootstrap from numpy.random import normal # =============================== # UTILITAIRES # =============================== def normalize_matrix(M): M = np.array(M, dtype=float) M -= M.min() if M.max() > 0: M /= M.max() return M def add_noise(M, sigma): noise = normal(0, sigma, M.shape) N = M + noise return np.clip((N + N.T) / 2, 0, 1) # =============================== # ETAPE 1 — EXTRACTION DES MOTIFS # =============================== def extract_cycles(M, k_min=3, k_max=6, threshold=0.0): G = nx.Graph() n = M.shape[0] for i in range(n): for j in range(i + 1, n): if M[i, j] > threshold: G.add_edge(i, j) cycles = [] for k in range(k_min, k_max + 1): for nodes in combinations(G.nodes, k): sub = G.subgraph(nodes) if nx.is_connected(sub) and sub.number_of_edges() >= k: cycles.append(list(nodes)) return cycles # =============================== # ETAPE 2 — MESURES LOCALES # =============================== def motif_trace(M, motif): return np.trace(M[np.ix_(motif, motif)]) # =============================== # ETAPE 3 — INDICE GLOBAL # =============================== def compute_index(M, motifs): S = np.array([motif_trace(M, c) for c in motifs]) return S, S.mean() # =============================== # ETAPE 4 — STABILITE # =============================== def stability_test(M, motifs, sigma=0.05, runs=300): indices = [] for _ in range(runs): Mn = add_noise(M, sigma) _, I = compute_index(Mn, motifs) indices.append(I) return np.mean(indices), abs(np.mean(indices) - np.mean(indices)) # =============================== # ETAPE 5 — BOOTSTRAP # =============================== def bootstrap_ci(S): res = bootstrap((S,), np.mean, confidence_level=0.95, n_resamples=2000) return res.confidence_interval.low, res.confidence_interval.high # =============================== # ETAPE 6 — CONTRIBUTION # =============================== def contribution_map(motifs, S, n): C = np.zeros(n) for s, motif in zip(S, motifs): for j in motif: C[j] += s / len(motif) return C def entropy(C): p = C / np.sum(C) p = p[p > 0] return -np.sum(p * np.log(p)) # =============================== # PROTOCOLE COMPLET # =============================== def run_protocol(M, epsilon_ratio=0.1): M = normalize_matrix(M) n = M.shape[0] motifs = extract_cycles(M) m = len(motifs) if m < 5: return {"verdict": "FAILURE", "reason": "motifs < 5"} S, I = compute_index(M, motifs) I_stable, delta = stability_test(M, motifs) low, high = bootstrap_ci(S) C = contribution_map(motifs, S, n) H = entropy(C) epsilon = epsilon_ratio * abs(I) # CONTROLES conditions = { "C1": m >= 5, "C2": I != 0, "C3": delta 0: M /= M.max() return (M + M.T) / 2 # =============================== # BRUIT # =============================== def add_noise(M, sigma): N = M + normal(0, sigma, M.shape) return np.clip((N + N.T) / 2, 0, 1) # =============================== # EXTRACTION NORMATIVE DES MOTIFS # =============================== def extract_cycles(M, k_min=3, k_max=6, threshold=0.0): G = nx.Graph() n = M.shape[0] for i in range(n): for j in range(i + 1, n): if M[i, j] > threshold: G.add_edge(i, j) basis = nx.cycle_basis(G) return [c for c in basis if k_min
Publication details
- Journal / source
- Zenodo (CERN European Organization for Nuclear Research)
- Publication date
- 8 January 2026