#![cfg(feature = "inference")]

// Human-Alignment Procrustes module for cognitive fidelity
// Implements optimal rotation to align model embeddings with human behavioral targets.

use mimirs_wyrd::Tensor;
use nalgebra::DMatrix;

/// A transformation layer that aligns model embeddings with human behavioral data (Centaur pass).
/// Implements pure Procrustes rotation: E_aligned = E · W.
#[derive(Debug, Clone)]
pub struct ProcrustesAligner {
    /// Rotation matrix [dim, dim]
    pub rotation: Tensor,
}

impl ProcrustesAligner {
    /// Opna - Creates a new aligner with the given rotation matrix.
    pub fn new(rotation: Tensor) -> Self {
        Self { rotation }
    }

    /// Applies the alignment transformation to an embedding tensor.
    pub fn align(&self, embedding: &Tensor) -> Result<Tensor, mimirs_wyrd::WyrdError> {
        // Implementation of Phase 9 spec: E_aligned = E · W
        embedding.matmul(&self.rotation)
    }
}

/// Performs Procrustes alignment between embeddings and target matrices.
///
/// Finds the orthogonal matrix W that minimizes ||E·W - T||_F (Frobenius norm).
///
/// # Arguments
/// * `embeddings` - Matrix of shape (n_tokens, d_model) with transformer embeddings
/// * `targets` - Matrix of same shape with human behavioral similarity targets
///
/// # Returns
/// A tuple of (aligned_embeddings, rotation_matrix W)
///
/// # Algorithm
/// 1. Compute M = T^T · E
/// 2. SVD: M = U · S · V^T
/// 3. Optimal rotation: W = V · U^T
/// 4. Return E_aligned = E · W
///
/// DERIVATION: Minimizing ||EW - T||_F subject to W^T W = I.
/// Expanding the norm: ||EW||² + ||T||² - 2tr(W^T E^T T).
/// Maximizing tr(W^T M) where M = E^T T (or T^T E depending on row/col conv).
/// For M = U Σ V^T, the optimal orthogonal W is V U^T.
pub fn procrustes_align(
    embeddings: &DMatrix<f32>,
    targets: &DMatrix<f32>,
) -> (DMatrix<f32>, DMatrix<f32>) {
    // Validate input dimensions
    debug_assert_eq!(embeddings.nrows(), targets.nrows(), "Rows must match");
    debug_assert_eq!(embeddings.ncols(), targets.ncols(), "Cols must match");

    // 1. Compute M = T^T · E
    let m = targets.transpose() * embeddings;

    // 2. SVD: M = U · S · V^T
    let svd = m.svd(true, true);
    let u = svd.u.expect("SVD U failed");
    let v_t = svd.v_t.expect("SVD V_t failed");

    // 3. Optimal rotation: W = V · U^T
    let w = v_t.transpose() * u.transpose();

    // 4. Return E_aligned = E · W
    let aligned = embeddings * &w;
    (aligned, w)
}
