*! version 1.0 P.MILLAR 18Mar2005
*! This software can be used for non-commercial purposes only.
*! The copyright is retained by the developer.
*! Copyright 2005 Paul Millar
program define matsort, rclass
version 7.0
args matname sortcol dir rankonly
/* --------------------------- */
/* This program sorts a matrix */
/* --------------------------- */

capture matrix list `matname'
if _rc != 0 {
  di as error "`matname' is not a matrix"
  exit 198
  }

/* set default values */
if "`dir'" == "" {
  local dir = "u"
  }
if "`sortcol'" == "" {
  local sortcol=1
  }
if "`rankonly'" == "" {
  local rankonly="replace"
  }

tempname A

local dir=substr("`dir'",1,1)
if "`dir'" == "d" {
  local down=1
  }
else if "`dir'" == "u" {
  local down=0
  }
else {
  di as error "Sort direction must be either up (for ascending) or down (for descending)"
  exit 198
  }

if "`rankonly'" == "replace" {
  local replace=1
  }
else if "`rankonly'" == "rankonly" {
  local replace=0
  }
else {
  di as error "Replace option must be either replace or rankonly: `rankonly'"
  exit 198
  }

matrix `A' = `matname'

local nrows = rowsof(`A')
local ncols = colsof(`A')
if `sortcol' > `ncols' | `sortcol' < 1 {
  di as error "Invalid column number specified: `sortcol'"
  exit 198
  }

// di "About to sort matrix `matname', sortcol=`sortcol', dir=`dir', nrows=`nrows', ncols=`ncols'"

local names : rownames `A'
tokenize `names'

/* initialize */
matrix rank = J(`nrows',1,0)
matrix order = J(`nrows',1,0)
forvalues i=1/`nrows' {
  matrix order[`i',1]=`i'
  }

/* ----------- */
/* now we sort */
/* ----------- */
forvalues i=1/`nrows' {
// di "matrix element `i', value=" `A'[`i',`sortcol']
  local max=  -2147483647
  local min=   2147483620
  local highest=0
  forvalues j=`i'/`nrows' {
    local curval=`A'[`j',`sortcol']
    if (`down'==1 & `max' < `curval') | (`down'==0 & `min' > `curval')  {
      local highest = `j'
      local max = `curval'
      local min = `curval'
      }
    }
// di "found the best value=" %7.6f `A'[`highest',`sortcol'] ", at " %3.0f `i' ", switching with " %3.0f `highest' " and ``i'' with ``highest''"
  local saver=order[`i',1]
  matrix order[`i',1]=order[`highest',1]
  matrix order[`highest',1]=`saver'
  forvalues k=1/`ncols' {
    local saver=`A'[`i',`k']
    matrix `A'[`i',`k']=`A'[`highest',`k']
    matrix `A'[`highest',`k']=`saver'
    }
  }

forvalues i=1/`nrows' {
  local j=order[`i',1]
  matrix rank[`j',1]=`i'
  }

local rn1=" "
local nrn=1
forvalues i=1/`nrows' {
  local row=order[`i',1]
  local lstr=length("`rn`nrn''")+length(" ``row''")
  if `lstr' > 80 {
    local nrn=`nrn'+1
    local rn`nrn'=" "
    }
  local rn`nrn'="`rn`nrn''" + " ``row''"
// di "`i':`row'"
// di "rn`nrn'=`rn`nrn''"
  }

mat rownames `A'=`rn1' `rn2' `rn3' `rn4' `rn5' `rn6' `rn7' `rn8' `rn9' `rn10' `rn11' `rn12' `rn13' `rn14' `rn15' `rn16' `rn17' `rn18' `rn19' `rn20'  `rn21' `rn22' `rn23' `rn24' `rn25' `rn26' `rn27' `rn28' `rn29' `rn30'  `rn31' `rn32' `rn33' `rn34' `rn35' `rn36' `rn37' `rn38' `rn39' `rn40' `rn41' `rn42' `rn43' `rn44' `rn45' `rn46' `rn47' `rn48' `rn49' `rn50'
if `replace' == 1 {
  mat `matname'=`A'
  }
mat drop `A'
return matrix rank = rank
return matrix order = order

end