##
## Linear Regression Package for perl
## intended to be 'required'
##

##
## y = A + Bx
##
## B = (n * Sum(xy) - Sum(x) * Sum(y)) / (n * Sum(x^2) - Sum(x)^2)
##
## A = (Sum(y) - B * Sum(x)) / n
##

*lr_init   = *lr'lr_init;
*lr_sample = *lr'lr_sample;
*lr_Y      = *lr'lr_Y;
*lr_X      = *lr'lr_X;
*lr_r      = *lr'lr_r;
*lr_cov    = *lr'lr_cov;
*lr_A      = *lr'lr_A;
*lr_B      = *lr'lr_B;

package lr;

sub tagify
{
    local($tag) = @_;
    if (defined($tag))
    {
      *lr_n   = eval "*${tag}_n";
      *lr_sx  = eval "*${tag}_sx";
      *lr_sx2 = eval "*${tag}_sx2";
      *lr_sxy = eval "*${tag}_sxy";
      *lr_sy  = eval "*${tag}_sy";
      *lr_sy2 = eval "*${tag}_sy2";
    }
}

sub lr_init
{
    &tagify($_[$[]) if defined($_[$[]);

    $lr_n   = 0;
    $lr_sx  = 0.0;
    $lr_sx2 = 0.0;
    $lr_sxy = 0.0;
    $lr_sy  = 0.0;
    $lr_sy2 = 0.0;
}

sub lr_sample
{
    local($_x, $_y) = @_;

    &tagify($_[$[+2]) if defined($_[$[+2]);

    $lr_n++;
    $lr_sx  += $_x;
    $lr_sy  += $_y;
    $lr_sxy += $_x * $_y;
    $lr_sx2 += $_x**2;
    $lr_sy2 += $_y**2;
}

sub lr_B
{
    &tagify($_[$[]) if defined($_[$[]);

    return 1 unless ($lr_n * $lr_sx2 - $lr_sx**2);
    return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / ($lr_n * $lr_sx2 - $lr_sx**2);
}

sub lr_A
{
    &tagify($_[$[]) if defined($_[$[]);

    return ($lr_sy - &lr_B * $lr_sx) / $lr_n;
}

sub lr_Y
{
    &tagify($_[$[]) if defined($_[$[]);

    return &lr_A + &lr_B * $_[$[];
}

sub lr_X
{
    &tagify($_[$[]) if defined($_[$[]);

    return ($_[$[] - &lr_A) / &lr_B;
}

sub lr_r
{
    &tagify($_[$[]) if defined($_[$[]);

    local($s) = ($lr_n * $lr_sx2 - $lr_sx**2) * ($lr_n * $lr_sy2 - $lr_sy**2);

    return 1 unless $s;
    
    return ($lr_n * $lr_sxy - $lr_sx * $lr_sy) / sqrt($s);
}

sub lr_cov
{
    &tagify($_[$[]) if defined($_[$[]);

    return ($lr_sxy - $lr_sx * $lr_sy / $lr_n) / ($lr_n - 1);
}

&lr_init();

1;
