Skip to main content

sc_neurocore_engine/scpn/
metrics.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later | Commercial license available
2// © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
3// © Code 2020–2026 Miroslav Šotek. All rights reserved.
4// ORCID: 0009-0009-3560-0851
5// Contact: www.anulum.li | protoscience@anulum.li
6// SC-NeuroCore — SCPN Metrics
7
8//! # SCPN Metrics
9//!
10//! Composite metrics computed from multi-layer SCPN outputs.
11
12/// SCPN-wide metrics computed from the 7-layer outputs.
13pub struct SCPNMetrics;
14
15impl SCPNMetrics {
16    /// Compute weighted global coherence across all layers.
17    /// weights: per-layer importance weights (7,)
18    /// metrics: per-layer global metric values (7,)
19    /// Returns: weighted average coherence ∈ [0, 1]
20    pub fn global_coherence(weights: &[f64; 7], metrics: &[f64; 7]) -> f64 {
21        let mut weighted_sum = 0.0_f64;
22        let mut weight_total = 0.0_f64;
23
24        for idx in 0..7 {
25            let weight = weights[idx].max(0.0);
26            let metric = metrics[idx].clamp(0.0, 1.0);
27            weighted_sum += weight * metric;
28            weight_total += weight;
29        }
30
31        if weight_total == 0.0 {
32            0.0
33        } else {
34            (weighted_sum / weight_total).clamp(0.0, 1.0)
35        }
36    }
37
38    /// Compute the "consciousness index" — a composite score
39    /// based on cross-layer synchronization.
40    /// phases_l4: Kuramoto phases from L4
41    /// glyph_l7: Glyph vector from L7
42    /// Returns: index ∈ [0, 1]
43    pub fn consciousness_index(phases_l4: &[f64], glyph_l7: &[f64; 6]) -> f64 {
44        let phase_sync = if phases_l4.is_empty() {
45            0.0
46        } else {
47            let n_inv = 1.0 / phases_l4.len() as f64;
48            let mean_cos = phases_l4.iter().map(|theta| theta.cos()).sum::<f64>() * n_inv;
49            let mean_sin = phases_l4.iter().map(|theta| theta.sin()).sum::<f64>() * n_inv;
50            (mean_cos * mean_cos + mean_sin * mean_sin)
51                .sqrt()
52                .clamp(0.0, 1.0)
53        };
54
55        let glyph_norm =
56            (glyph_l7.iter().map(|v| v * v).sum::<f64>().sqrt() / (6.0_f64).sqrt()).clamp(0.0, 1.0);
57
58        (0.7 * phase_sync + 0.3 * glyph_norm).clamp(0.0, 1.0)
59    }
60}