pro sixlin,xx,yy,a,siga,b,sigb,weight=weight
;+
; NAME:
;       SIXLIN
; PURPOSE:
;       Compute linear regression coefficients by six different methods.
; EXPLANATION:
;       Adapted from the FORTRAN program (Rev. 1.1)  supplied by Isobe, 
;       Feigelson, Akritas, and Babu Ap. J. Vol. 364, p. 104 (1990).   
;       Suggested when there is no understanding about the nature of the 
;       scatter about a linear relation, and NOT when the errors in the 
;       variable are calculable.
;
; CALLING SEQUENCE:
;       SIXLIN, xx, yy, a, siga, b, sigb, [WEIGHT = ]  
;
; INPUTS:
;       XX - vector of X values
;       YY - vector of Y values, same number of elements as XX
;
; OUTPUTS:
;       A - Vector of 6 Y intercept coefficients
;       SIGA - Vector of standard deviations of 6 Y intercepts
;       B - Vector of 6 slope coefficients
;       SIGB - Vector of standard deviations of slope coefficients
;
;       The output variables are computed using linear regression for each of 
;       the following 6 cases:
;               (0) Ordinary Least Squares (OLS) Y vs. X (c.f. linfit.pro)
;               (1) Ordinary Least Squares  X vs. Y
;               (2) Ordinary Least Squares Bisector
;               (3) Orthogonal Reduced Major Axis
;               (4) Reduced Major-Axis 
;               (5) Mean ordinary Least Squares
;
; OPTIONAL INPUT KEYWORD:
;      WEIGHT -  vector of weights, same number of elements as XX and YY
;                For 1 sigma Gausssian errors, the weights are 1/sigma^2 but
;                the weight vector can be more general.   Default is no 
;                weighting. 
; NOTES:
;       Isobe et al. make the following recommendations
;
;       (1) If the different linear regression methods yield similar results
;               then quoting OLS(Y|X) is probably the most familiar.
;
;       (2) If the linear relation is to be used to predict Y vs. X then
;               OLS(Y|X) should be used.   
;
;       (3) If the goal is to determine the functional relationship between
;               X and Y then the OLS bisector is recommended.
;
; REVISION HISTORY:
;       Written   Wayne Landsman          February, 1991         
;       Corrected sigma calculations      February, 1992
;       Converted to IDL V5.0   W. Landsman   September 1997
;       Added WEIGHT keyword   J. Moustakas   Februrary 2007
;-
 compile_opt idl2
 On_error, 2                                   ;Return to Caller

 if N_params() LT 5 then begin   
    print,'Syntax - SIXLIN, xx, yy, a, siga, b, sigb, {WEIGHT =]'   
    return
  endif

 b = dblarr(6) &  siga = b & sigb =b
 x = double(xx)      ;Keep input X and Y vectors unmodified
 y = double(yy)
 rn = N_elements(x)

 if rn LT 2 then $
    message,'Input X and Y vectors must contain at least 2 data points'

 if rn NE N_elements(y) then $
    message,'Input X and Y vectors must contain equal number of data points'

 if (n_elements(weight) eq 0L) then weight = replicate(1.0,rn) else begin
    if (rn ne n_elements(weight)) then $
      message,'Input X and WEIGHT vectors must contain equal number of data points'
 endelse
 
; Compute averages and sums

 sumw = total(weight) 
 
 xavg = total( weight * x)/sumw
 yavg = total( weight * y)/sumw
 x = x - xavg
 y = y - yavg
 sxx = total( weight * x^2)
 syy = total( weight * y^2)
 sxy = total( weight * x*y)
 if sxy EQ 0. then $
      message,'SXY is zero, SIXLIN is terminated'
 if sxy LT 0. then sign = -1.0 else sign = 1.0

; Compute the slope coefficients

 b[0] = sxy / sxx
 b[1] = syy / sxy
 b[2] = (b[0]*b[1] - 1.D + sqrt((1.D + b[0]^2)*(1.D +b[1]^2)))/(b[0] + b[1] )
 b[3] = 0.5 * ( b[1] - 1.D/b[0] + sign*sqrt(4.0D + (b[1]-1.0/b[0])^2))
 b[4] = sign*sqrt( b[0]*b[1] )
 b[5] = 0.5 * ( b[0] + b[1] )

; Compute Intercept Coefficients

 a = yavg - b*xavg

;  Prepare for computation of variances

 gam1 = b[2] / ( (b[0] + b[1]) *   $
         sqrt( (1.D + b[0]^2)*(1.D + b[1]^2)) )
 gam2 = b[3] / (sqrt( 4.D*b[0]^2 + ( b[0]*b[1] - 1.D)^2))
 sum1 = total( weight * ( x*( y - b[0]*x ) )^2)
 sum2 = total( weight * ( y*( y - b[1]*x ) )^2)
 sum3 = total( weight * x * y * ( y - b[0]*x) * (y - b[1]*x ) )
 cov = sum3 / ( b[0]*sxx^2 )

; Compute variances of the slope coefficients

 sigb[0] = sum1 / sxx^2
 sigb[1] = sum2 / sxy^2
 sigb[2] = (gam1^2) * ( ( (1.D + b[1]^2) ^2 )*sigb[0] +  $
                  2.D*(1.D + b[0]^2) * (1.D + b[1]^2)*cov + $
                  (  (1.D + b[0]^2)^2)*sigb[1] )
 sigb[3] = (gam2^2)*( sigb[0]/b[0]^2 + 2.D*cov + b[0]^2*sigb[1] )
 sigb[4] = 0.25*(b[1]*sigb[1]/b[1] + $
                     2.D*cov + b[0]*sigb[1]/b[1] )
 sigb[5] = 0.25*(sigb[0] + 2.D*cov + sigb[1] )

; Compute variances of the intercept coefficients

 siga[0] = total( weight * ( ( y - b[0]*x) * (1.D - sumw*xavg*x/sxx) )^2 )
 siga[1] = total( weight * ( ( y - b[1]*x) * (1.D - sumw*xavg*y/sxy) )^2 ) 
 siga[2] = total( weight * ( (x * (y - b[0]*x) * (1.D + b[1]^2) / sxx + $
                  y * (y - b[1]*x) * (1.D + b[0]^2) / sxy)*  $
                  gam1 * xavg * sumw - y + b[2] * x) ^ 2)
 siga[3] = total( weight * ( ( x * ( y - b[0]*x) / sxx + $
                   y * ( y - b[1]*x) * b[0]^2/ sxy) * gam2 * $
                   xavg * sumw / sqrt( b[0]^2) - y + b[3]*x) ^ 2 )
 siga[4] = total( weight * ( ( x * ( y - b[0] * x) * sqrt( b[1] / b[0] ) / sxx + $
                   y * ( y - b[1] * x) * sqrt( b[0] / b[1] ) / sxy) * $
                  0.5 * sumw * xavg - y + b[4] * x)^2 )

 siga[5] = total( weight * ( (x * ( y - b[0] * x) / sxx +  $
                  y * ( y - b[1] * x) / sxy)*    $
                  0.5 * sumw * xavg - y + b[5]*x )^2 )

; Convert variances to standard deviation

 sigb = sqrt(sigb)
 siga = sqrt(siga)/sumw
 
 return
 end