```
/*
The list 'in' (or matrix 'm') of treatment effects must contain
values that are suitable for ranking.
(For example in forecasting applications it would have
to be several series of forecast errors, or losses.)
For matrix input the variables (or different "treatments") must
be in columns.
Output is a 4-element vector of
- test stat
- pvalue
- test conclusion at 5% (reject = 1, not reject = 0)
- test conclusion at 1%
For small samples the pvalue may be NA, whenever the
Chi2-approximation is not used anymore.
(This is different in R, apparently.)
Critical values for small samples are taken from
https://www.york.ac.uk/depts/maths/tables/friedman.pdf
and partly cross-checked with tables from the (German) book
Buening & Trenkler, Nichtparametrische Methoden, 2nd ed. 1994.
*/
if !exists(in) && !exists(m)
funcerr "Need some input"
elif !exists(m)
mhasranks = 0 # just to be safe, otherwise contradictory
smpl in --no-missing
m = {in}
endif
set warnings off
matrix out = {NA; NA; 0; 0}
set warnings on
N = rows(m) # 'blocks', or obs
K = cols(m) # 'groups', or 'treatments'
# calculate the ranks
if !mhasranks
rankrows(&m)
endif
# loop i = 1..rows(m) -q
# m[i, ] = ranking(m[i, ])
# endloop
matrix r_j = meanc(m)
scalar rbar = sum(m) / (N * K)
scalar SSt = N * (r_j - rbar) * (r_j - rbar)'
scalar SSe = sum( (m - rbar).^2 ) / (N * (K-1))
out[1] = SSt / SSe
# Large-sample approximation
if N > 15 || K > 4
out[2] = pvalue(c, K-1, out[1])
if out[2] < 0.01
out[3:4] = {1; 1}
elif out[2] < 0.05
out[3:4] = {1; 0}
else
out[3:4] = {0; 0}
endif
elif K < 3 || (K == 3 && N == 2) || N == 1
if verbose
print "Warning: sample too small, no critical values"
# out will be: {stat, NA, 0, 0}
endif
else # K is 3 or 4 and N is <= 15; no p-value possible
if verbose
print "Warning: small sample, no p-values"
endif
matrix cv = FriedmanTables(N, K)
if out[1] > cv[2] # at 1% level
out[3:4] = {1; 1}
elif out[1] > cv[1] # at 5% level
out[3:4] = {1; 0}
endif
endif
if verbose
printf "Friedman test results with %d blocks and %d 'treatments':\n", N, K
if ok(out[2])
printf " Chi2(%d) stat %g, pvalue %g\n", K-1, out[1], out[2]
elif out[4] == 1
printf " Small-sample test stat %g, rejection at 1\% level\n", out[1]
elif out[3] == 1
printf " Small-sample test stat %g, rejection at 5\% level\n", out[1]
else
printf " Small-sample test stat %g, no rejection at 5\% level\n", out[1]
endif
endif
return out
```

```
/*
Quade, D. (1979). Using weighted rankings in the analysis of
complete blocks with additive block effects, Journal of the
American Statistical Association 74: 680–683.
# based on the description at
# http://www.itl.nist.gov/div898/software/dataplot/refman1/auxillar/quade.htm
Output is a two-element col vector with
test stat and p-value (from F approximate distribution).
*/
if !exists(in) && !exists(m)
funcerr "Need some input"
elif !exists(m)
mhasranks = 0 # just to be safe, otherwise contradictory
smpl in --no-missing
m = {in}
endif
N = rows(m) # 'blocks', or obs
K = cols(m) # 'groups', or 'treatments'
# calculate row ranges and rank them
matrix Qi = ranking( maxr(m) - minr(m) ) # column vector
# now calculate the ranks
rankrows(&m)
# actual calculations
matrix Sij = Qi .* (m - ((K+1) / 2) ) # scores
matrix Sj = sumc(Sij) # row vector
scalar A2 = sum(Sij .^2) # total sum squares (Anova)
scalar B = sumr(Sj .^2) / N # treatment sum squares (Anova)
T3 = (N-1) * B / (A2 - B) # test stat
pval = pvalue(F, K-1, (N-1)*(K-1), T3)
if verbose
printf "Quade test results with %d blocks and %d 'treatments':\n", N, K
printf " F(%d, %d), stat %g, pvalue %g\n", K-1, (N-1)*(K-1), T3, pval
endif
return {T3; pval}
```

```
# factor out this function to avoid double calculations,
# and easier optimizations in the future
# (Might be obsoleted in the future when hansl's builtin ranking function
# would accept a matrix argument.)
# calculate the ranks
loop i = 1..rows(m) -q
m[i, ] = ranking(m[i, ])
endloop
```

```
# First element 5%, second 1%.
# Source https://www.york.ac.uk/depts/maths/tables/friedman.pdf
# (some rounding --and typos?-- applied)
if N == 2 && K == 3
return {NA, NA}
elif K == 3
# starts with N == 3
matrix cv = {6, NA; 6.5, 8; 6.4, 8.4; 7, 9; 7.14, 8.86; 6.25, 9; 6.22, 9.56; 6.2, 9.6; 6.54, 9.46; 6.5, 9.5; 6.62, 9.39; 6.14, 9.14; 6.4, 8.93}
return cv[N-2, ]
elif K == 4
# starts with N == 2
matrix cv = {6, NA; 7.4, 9; 7.8, 9.6; 7.8, 9.96; 7.6, 10.2; 7.8, 10.54; 7.65, 10.50; 7.67, 10.73; 7.68, 10.68; 7.69, 10.75; 7.7, 10.8; 7.8, 10.85; 7.71, 10.89; 7.72, 10.92}
return cv[N-1, ]
else
funcerr "shouldn't happen"
endif
```