clear; clc; close all;                 % Clear workspace, command window, and close all figures
addpath('./libs4clustering');         % Add path to utility functions used for clustering

%% 🌟 Geometry-Inspired Tensor Clustering Banner 🌟
fprintf('\n');
fprintf('╔════════════════════════════════════════════════════════════════════════════╗\n');
fprintf('║               🌐 t-Product Geometry-Inspired Tensor Clustering              \n');
fprintf('║                                                                             \n');
fprintf('║   📐 The method is directly inspired by  t-product geometry:                \n');
fprintf('║      - Each face image tensor is modeled as a structured t-module           \n');
fprintf('║        under the t-product algebra with transform-domain regularity.        \n');
fprintf('║      - The BTR model enforces low-rankness along both mode-1 (rows) and     \n');
fprintf('║        mode-2 (columns), forming a bidirectional t-module representation.   \n');
fprintf('║      - This dual-mode coupling introduces non-flat curvature into the       \n');
fprintf('║        tensor manifold, enabling richer structural characterization.        \n');
fprintf('║                                                                             \n');
fprintf('║   🎯 In this experiment, we apply BTR to cluster aligned face images        \n');
fprintf('║      from the PIE dataset, leveraging both horizontal and vertical          \n');
fprintf('║      spatial dependencies in the transform domain.                          \n');
fprintf('╚════════════════════════════════════════════════════════════════════════════╝\n\n');

%% ---------------- Load and Prepare Data ----------------
% Load PIE_face_10 dataset (aligned face images and ground truth labels)
load('PIE_face_10.mat');  

% Reshape and permute to form tensor X: height × sample × width
X = reshape(X{1}, 22, 22, 680); 
X = permute(X, [1, 3, 2]);      % Now X is 22 × 680 × 22 (height × num_images × width)
labels = gt;                    % Load ground truth labels

% Get tensor dimensions
[n1, n2, n3] = size(X);         % n1 = height, n2 = #samples, n3 = width

%% ---------------- Define Transforms and Parameters ----------------
% Thresholds for row and column t-module low-rank modeling
tho  = 100;                     % Rank threshold for row direction
thot = 100;                     % Rank threshold for column direction
max_iter = 500;                % Max iterations for optimization

% Define forward/inverse transforms for mode-3 and mode-1 respectively (FFT-based)
transformRow.L        = @fft; transformRow.l = n3; transformRow.inverseL = @ifft;
transformCol.L        = @fft; transformCol.l = n1; transformCol.inverseL = @ifft;

%% ---------------- Compute Low-Rank Approximations ----------------
% Row-direction approximation: X ≈ U_x * S_x * V_x'
[~, ~, U_x, V_x, S_x] = prox_low_rank(X, tho, transformRow);
LL = tprod(U_x, S_x, transformRow);  % Approximate signal in mode-3 transform domain

% Column-direction approximation: permute X and repeat process
Xt = permute(X, [3, 2, 1]);          % Move width to first mode
[~, ~, Ut_x, Vt_x, St_x] = prox_low_rank(Xt, thot, transformCol);
LLt = tprod(Ut_x, St_x, transformCol);

%% ---------------- Regularization Setup ----------------
alpha = 0.1;                         % Weight for coupling constraint in BTR
tsn_X  = tsn(X, transformRow);      % Pre-transform for row direction
tsn_Xt = tsn(Xt, transformCol);     % Pre-transform for column direction

% Adaptive λ for regularization strength based on tensor size
lambdaBTR = min(1/sqrt(max(n1, n2)*n3), 1/sqrt(max(n3, n2)*n1));

%% ---------------- Solve BTR Model (Previously Called OR-DLRR) ----------------
dbgInfo.Enabled = 0;                % Turn off debug information

% Core optimization: recover coefficient tensors W and R in both directions
[W_BTR, R_BTR, ~, ~, E_BTR, ~] = ...
    R_DLRR(X, LL, LLt, alpha, lambdaBTR, transformRow, transformCol, max_iter, dbgInfo);

%% ---------------- Construct Affinity and Cluster ----------------
% Compute bidirectional affinity matrices from coefficients
Zg1 = tprod(V_x,  W_BTR);           % Row-direction similarity
Zg2 = tprod(Vt_x, R_BTR);           % Column-direction similarity

% Perform spectral clustering using normalized cuts on combined affinity
t = 0.01;  % Threshold for spectral affinity sparsification
resClusterBTR = ncut_clustering_doubleZ(Zg1, Zg2, 0.5, labels', t);

%% ---------------- Display Final Clustering Results ----------------
% Results contain: ACC (accuracy), NMI (normalized mutual information), PUR (purity)
resultsTable = table("BTR", resClusterBTR(1), resClusterBTR(2), resClusterBTR(3), ...
    'VariableNames', {'Algorithm','Mean_ACC', 'Mean_NMI', 'Mean_PUR'});

% Output results
disp(resultsTable);
