#!/usr/bin/perl 

use 5.038.2;

use Memoize qw(memoize);

memoize "mean";

my $DEBUG = 0;
my $version = 0.02;

# Análisis de varianza A.N.O.V.A. clásico de experimentos
# En concreto el rectángulo de datos conocido como «cuadrado latino»
# No necesita ser un cuadrado: hay H0 y H1 frente a diferentes columnas de observaciones
# y unos samples de tamaño $treatment en cada 'casilla'  

######################################## DATA

# base 1 to take it easy

my $rows = 2;                    # números pequeños son muchos datos, p.ej. ébola 
my $cols = 6;
my $treatment = 3;

                                                                                                 # # justo igual que el ejemplo de C.M. Cuadras,
                                                                                                 # # «Inferencia Estadística», vol. 2, 5.ª edición, ~ 1982.

# -+- No es relevante, porque el libro estaba equivocado: sospeché cuando r multiplicaba un sumatorio

my @data;
my @serialize;
my @serial;                      # esto toadvía no he dedidido si conviene tmp o no -> R x R

for my $r (1 .. $rows) {
    for my $c (1 .. $cols) {
	@serial = ();
	for my $t (1 .. $treatment) {                          # este orden es importante: se tienen varios datos de cada tratamiento  
	    $data[$r][$t][$c] = 1 + rand() + log($t);          # dato inventado, chupadísímo
	    push @serial, $data[$r][$t][$c];                   # esto importa, y no debería estar aquí de mano, sino más tarde, licencia poética
	}
	push @serialize, @serial;
    }
}


####################################### Ya tengo datos, eso en la vida real significa ir a la macrodiscoteca varias veces

# Fase 2: calculamos los sumatorios signinificantes para cada grupo de datos (fila, columna, tratamiento y residuos)

my $glt = $treatment - 1;     # lo mismo, pero lo mismo, 2
my $glr = $rows - 1;          # grados de libertad de estos, 1 
my $glc = $cols - 1;          # lo mismo, pero cifra diferente, 8 
my $glerr = ($rows - 1) * ($cols - 2); # esto es una combinación de 2 cosas, los g.d.l. se restan en cada lado

# ..........................................................................................................................

# Fase 3: grados de libertad y errores

# esta es la hipótesis nula, el tratamiento, lo más interesante del experimento, lo que se mide
my @errortreatments = (0) x ($cols+1);    # H0: tratamiento 
for my $r ( 1 .. $rows ){
    for my $t ( 1 .. $treatment ){
	$errortreatments[$_] += ($data[$r][$t][$_] - mean(@serialize))**2 for ( 1 .. $cols );
    }
}
# -> ratio que muestra la varialidad treat over sample
for my $t ( 1 .. $treatment ){                              
    say "Error de la hipótesis neutra de columnas = $errortreatments[$t]" if $DEBUG;
    say "Coeficente F de ErrorColsTreat \/ glt = ", $errortreatments[$t] / $glt, "   grados de libertad $glt   ";
}
# ..........................................................................................................................

my @errorrows = (0) x ($rows+1);         
for my $r ( 1 .. $rows ) {               # Filas -> Fila 2 es H1:
    for my $t ( 1 .. $treatment ){
	$errorrows[$r] += ($data[$r][$t][$_] - mean(@serialize))**2 for ( 1 .. $cols );
    }
}
for my $r ( 1 .. $rows ){                                 # 2 -> el que interesa conrespecto al errcol Cc
    say "Error del efecto fila de filas = $errorrows[$r]" if $DEBUG;
    say "Coeficiente F de ErrorFila \/ glr -> ", $errorrows[$r] / $glr, "   graados de libertad $glr   ";
}
# ..........................................................................................................................
  
my @errorcols = (0) x ($cols+1);
for my $c ( 1 .. $cols ) {               # variaciones (columnas) del tratamiento
    for my $t ( 1 .. $treatment ) {
	$errorcols[$c] += ($data[$_][$t][$c] - mean(@serialize))**2 for ( 1 .. $rows );
    }
}
for my $c ( 1 .. $cols ){ 
    say "Error de la hipótesis neutra de columnas = $errorcols[$c]" if $DEBUG;
    say "Coeficente F de ErrorCols \/ glc -> ", $errorcols[$c] / $glc, "   grados de lbertad $glc   ";
}
# ..........................................................................................................................
  
my $errortotal = 0;
for my $r ( 1 .. $rows ) {
    for my $c ( 1 .. $cols ) {
	for my $t ( 1 .. $treatment ) {
	    $errortotal += ( $data[$r][$t][$c] - mean(@serialize) )**2 for ( 1 .. $treatment );                  # suma de 4 errores: row, col, tratement, and residual
	}
    }
}
say "Error total \= $errortotal" if $DEBUG;

my $sumatotaldeerrores = $errortotal;      # IMPORTANTE: el error residual es el que queda después de restar los errores de fuente conocida
for my $r ( 1 .. $rows ){
    $sumatotaldeerrores -= $errorrows[$r];
}
for my $c ( 1 .. $cols ){
    $sumatotaldeerrores -= $errorcols[$c];
}
for my $t ( 1 .. $treatment ){ 
    $sumatotaldeerrores -= $errortreatments[$t];
}
say "index  ErrorTotal \/ glerr \-\> ", $sumatotaldeerrores / $glerr, "   grados de libertad $glerr   ";                        # 1 -> el máximo, el total y final 


###############################################################################################################################################################

# Fase 4: Calculados los valores críticos, ver si son significativos en la tablas de F

use Statistics::Distributions; 

for my $g ($glt, $glr, $glc){          # no se estudia aquí la distribución de los residuos 
    my $f = Statistics::Distributions::fdistr ($g , $glerr ,  0.001);
    print "F-crit ($g degree of freedom in numerator, $glerr degrees of freedom "
      . "in denominator, 99th percentile = 0.01 level) = $f\n";
}

# -----------------------------------------------------------------------------------------------------

say "\nEnd of $0 v$version at ", scalar(localtime()), "\n";

exit 2;


sub mean {
    my @y = @_;
    my $sum = 0;
    $sum += $_ for (1 .. scalar(@y));
    $sum /= scalar(@y);
    return $sum;
}


