<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="gfn2html.xsl"?>
<gretl-functions>
<gretl-function-package name="GFE" needs-panel-data="true" minver="2026b" lives-in-subdir="true">
<author email="valentini.f.90@gmail.com">Riccardo &quot;Jack&quot; Lucchetti and Alessandro Pionati and Francesco Valentini</author>
<version>0.1</version>
<date>2026-07-28</date>
<description>Grouped Fixed Effects for panel data</description>
<tags>C23</tags>
<help>
pdfdoc:GFE.pdf
</help>
<data-files count="1">
examples </data-files>
<gretl-function name="gfe_estimate" type="bundle">
 <params count="4">
  <param name="y" type="series" const="true"/>
  <param name="X" type="list"/>
  <param name="G" type="scalar"/>
  <param name="opt_in" type="bundle" optional="true"/>
 </params>
<code>chk = bal_test(y, X)
if !chk
  funcerr &quot;Panel is unbalanced. Not for now&quot;
endif
N = $nobs/$pd

# process options
opts = default_opts(G)
if exists(opt_in)
  opts = opt_in + opts
endif

# choose a sensible number of random starts if not given
if missing(opts.randstarts)
  if opts.algorithm == 1
    opts.randstarts = G &lt; 8 ? 1024 : 4096
  elif opts.algorithm == 2
    opts.randstarts = floor(8*sqrt(G))
  endif
endif

set stopwatch

if opts.BICselect
  printf &quot;%s\n&quot;, &quot;=&quot;*64
  printf &quot;   BIC model selection (Gmax = %d)\n&quot;, G
  printf &quot;%s\n&quot;, &quot;=&quot;*64

  opts.BICselect = 0
  verbose = opts.verbose
  opts.verbose = 0

  mod = gfe_estimate_fixed(y, X, G, opts)
  bestg = G
  T = mod.T
  K = mod.nreg
  ssr = mod.obj
  s2hat = ssr / ((N - G)*T - N - K)

  BICmax = BICrit(ssr, N, T, G, K, s2hat)
  if verbose
    printf &quot;%6.3g%% done\r&quot;, 100/G
    flush
  endif

  matrix BIC = {G, BICmax, ssr}
  bestBIC = BICmax

  loop g = (G-1) .. 2 --decr
    bundle b = gfe_estimate_fixed(y, X, g, opts)
    BICi = BICrit(b.obj, N, T, g, K, s2hat)
    if verbose
      printf &quot;%6.3g%% done\r&quot;, 100*(G-g+1)/G
      flush
    endif
    BIC |= {g, BICi, b.obj}
    if BICi &lt; bestBIC
      mod = b
      bestg = g
      bestBIC = BICi
    endif
  endloop

  if verbose
    printf &quot;   100%% done\n&quot;
  else
    printf &quot;\n&quot;
  endif
  flush

  list REG = const X
  if opts.tvar
    REG += dummify(time)
  endif
  ols y REG --quiet

  BICi = BICrit ($ess, N, T, 1, K, s2hat)
  BIC |= {1, BICi, $ess}
  if BICi &lt; bestBIC
    bestg = 1
  endif

  printf &quot;%s\n&quot;, &quot;-&quot;*32
  printf &quot; G\t    BIC\t    SSR\n&quot;
  printf &quot;%s\n&quot;, &quot;-&quot;*32
  loop i = 1 .. G
    printf &quot;%2d\t%7.4g\t%7.4g&quot;, i, BIC[G-i+1,2], BIC[G-i+1,3]
    if i == bestg
      printf &quot; *&quot;
    endif
    printf &quot;\n&quot;
  endloop
  printf &quot;%s\n&quot;, &quot;-&quot;*32

  opts.BICselect = 1
  opts.verbose = verbose
else
  mod = gfe_estimate_fixed(y, X, G, opts)
endif

err = add_sandwich(y, X, &amp;mod)
mod.etime = $stopwatch

if opts.verbose
  printf &quot;estimation done (obj = %g)\n&quot;, mod.obj
endif

mod.depvarname = argname(y)

return mod
</code>
</gretl-function>
<gretl-function name="gfe_printout" type="void">
 <params count="2">
  <param name="mod" type="bundle" const="true"/>
  <param name="showfreq" type="bool" default="0"/>
 </params>
<code>pn = mod.parnames
cs = mod.coeff ~ mod.stderr

opts = mod.opts
tvstr = opts.tvar ? &quot;time-varying&quot; : &quot;time-invariant&quot;

printf &quot;\n%s\n&quot;, &quot;=&quot;*64
printf &quot;Group fixed effects estimator &quot;

printf &quot;(algorithm %d)\n&quot;, opts.algorithm
if opts.algorithm == 1
  printf &quot;method = &quot;
  if opts.method == &quot;random&quot;
    printf &quot;%d random starts\n&quot;, opts.randstarts
  else
    printf &quot;%s\n&quot;, opts.method
  endif
else
  printf &quot;%d random starts, &quot;, opts.randstarts
  string extra = opts.parallel == 0 ? &quot;single-threaded&quot; : sprintf(&quot;%d processes&quot;, opts.parallel)
  printf &quot;%s\n&quot;, extra
endif

printf &quot;dependent variable: %s\n&quot;, mod.depvarname
printf &quot;Using %d units and %d time periods (%d total observations)\n&quot;, mod.N, mod.T, mod.N*mod.T
printf &quot;%d %s groups &quot;, opts.ngrp, tvstr

if mod.bootrep &gt; 0
  printf &quot;(bootstrap s.e., %d replications)\n&quot;, mod.bootrep
else
  printf &quot;(sandwich s.e.)\n&quot;
endif

printf &quot;%s\n&quot;, &quot;=&quot;*64
modprint cs pn
printf &quot;SSR = %g, Log-likelihood = %g\n&quot;, mod.obj, mod.lnl
printf &quot;Elapsed time = %g seconds\n\n&quot;, mod.etime

if showfreq
  printf &quot;Number of units per group:\n&quot;
  showfreq(mod.grp)
  printf &quot;\n&quot;
endif
</code>
</gretl-function>
<gretl-function name="group_fx" type="series">
 <params count="1">
  <param name="mod" type="bundle" const="true"/>
 </params>
<code>matrix paths = mshape(NA, mod.T, mod.N)
G = mod.opts.ngrp
if mod.opts.tvar
  loop i = 1 .. G
    sel = which(mod.grp .= i)
    paths[,sel] = mshape(mod.a[,i], $pd, nelem(sel))
  endloop
  series ret = vec(paths)
else
  tmp = replace(mod.grp, seq(1, G), mod.a)
  ret = pexpand(tmp)
endif
discrete ret
setinfo ret --description=&quot;Group effect&quot;
return ret
</code>
</gretl-function>
<gretl-function name="group_plot" type="void">
 <params count="2">
  <param name="mod" type="bundle" const="true"/>
  <param name="dest" type="string" optional="true"/>
 </params>
<code>opts = mod.opts
G = opts.ngrp
out = exists(dest) ? dest : &quot;display&quot;
tvar = opts.tvar
matrix plt = mod.a
s = seq(1, G)'
lab = &quot;group &quot; ~ s

title = &quot;Grouped fixed effects&quot;
if !tvar
  # a is a column vector
  plt = plt ~ s
  rnameset(plt, lab)
  cnameset(plt, &quot;alpha group&quot;)
  plot plt
    option with-boxes
    literal set linetype 1 pt 1 lc rgb &quot;#888888&quot;
    literal set boxwidth 0.75 relative
    literal set style fill solid 0.5
    literal set title '@title'
    printf &quot;set xrange [0:%d]&quot;, G+1
  end plot --output=@out
else
  plt = plt ~ seq(1, rows(plt))'
  lab += &quot;time&quot;
  cnameset(plt, lab)
  plot plt
    options with-lp single-yaxis
    literal set xlabel &quot;Time&quot;
    literal set ylabel &quot;Group effect&quot;
    literal set title '@title'
    printf &quot;set xrange [0:%d]&quot;, $pd+1
    literal set key outside right
  end plot --output=@out
endif
</code>
</gretl-function>
<gretl-function name="default_opts" type="bundle" private="1">
 <params count="1">
  <param name="G" type="scalar"/>
 </params>
<code>bundle ret = empty

ret.ngrp = G
ret.tvar = 1

ret.method     = &quot;random&quot;
ret.randstarts = NA
ret.bootiter   = 128

ret.algorithm  = 2
ret.verbose    = 1
ret.BICselect  = 0

# use MPI?
si = $sysinfo
ret.parallel = si.mpi * si.ncores

return ret
</code>
</gretl-function>
<gretl-function name="bal_test" type="scalar" private="1">
 <params count="2">
  <param name="y" type="series" const="true"/>
  <param name="X" type="list"/>
 </params>
<code>list ALL = y || X
series o = ok(ALL)
return min(o) == 1
</code>
</gretl-function>
<gretl-function name="BICrit" type="scalar" private="1">
 <params count="6">
  <param name="ssr" type="scalar"/>
  <param name="N" type="scalar"/>
  <param name="T" type="scalar"/>
  <param name="G" type="scalar"/>
  <param name="K" type="scalar"/>
  <param name="s2Gmax" type="scalar"/>
 </params>
<code>NT = N*T
ret = ssr/NT + s2Gmax * (G*T + N + K)/NT * log(NT)

return ret
</code>
</gretl-function>
<gretl-function name="init_groups" type="void" private="1">
 <params count="4">
  <param name="y" type="series" const="true"/>
  <param name="X" type="list"/>
  <param name="N" type="scalar"/>
  <param name="b" type="bundleref"/>
 </params>
<code>/* -doc-
provides a grouping of the units into n groups, according to
the parameter &quot;method&quot; key in the bundle b:

random:     discrete uniform
given:      basically a no-op, it just uses the matrix initgrp
residuals:  kmeans on pmeaned OLS residuals of y on X
kmeans:     kmeans on pmeaned y and X
kmeans-res: kmeans on the NxT matrix of OLS residuals
sorting:    based on sorted OLS residuals of y on X

The resulting grouping is stored into the bundle b, under the
key &quot;inigrp&quot;
*/

startmth = b.method
n = b.ngrp

if startmth == &quot;random&quot;
  grp = mrandgen(i, 1, n, N, 1)
elif startmth == &quot;given&quot;
  grp = b.inigrp
elif startmth == &quot;residuals&quot;
  ols y const X --quiet
  mean_u = pshrink(pmean($uhat))
  kmod = kmeans(mean_u, n)
  grp = kmod.cluster_id
elif startmth == &quot;kmeans-res&quot;
  matrix U = {}
  mols({y}, 1 ~ {X}, &amp;U)
  matrix U = mshape(U, $pd, N)'
  kmod = kmeans(U, n)
  grp = kmod.cluster_id
elif startmth == &quot;kmeans&quot;
  matrix tmp = pshrink(pmean(y))
  loop foreach i X
    tmp ~= pshrink(pmean(X.$i))
  endloop
  kmod = kmeans(tmp, n)
  grp = kmod.cluster_id
elif startmth == &quot;sorting&quot;
  ols y const X --quiet
  mean_u = pmean($uhat)
  m = msortby(pshrink(mean_u), 1)
  h = -msortby( -(m ~ diff(m)), 2 )
  limits = h[1:n, 1]
  grp = 1 + sumr(m .&gt; limits')
else
  funcerr &quot;unknown starting method\n&quot;
endif

b.inigrp = grp
</code>
</gretl-function>
<gretl-function name="update_step" type="bundle" private="1">
 <params count="6">
  <param name="y" type="series" const="true"/>
  <param name="X" type="list"/>
  <param name="ngrp" type="scalar"/>
  <param name="timevar" type="bool"/>
  <param name="grp" type="matrix" const="true"/>
  <param name="P2" type="scalar"/>
 </params>
<code>/* -doc-
Bonhomme-Manresa (2015) -- Updating step: compute the coefficients
given the groupings
*/

# for the time-varying model, interaction of unit and time \alpha_{g,t}
series group_id = timevar ? (pexpand(grp-1)) * P2 + time : pexpand(grp)
scalar nreg = nelem(X)

matrix e = {}
matrix a = {}
b = fols({y}, {X}, {group_id}, &amp;e, , &amp;a)
obj = e'e
loglik = -$nobs/2 * (2.8378770664 + log(obj/$nobs))
bundle ret = _(b, loglik, obj)

ret.a = timevar ? mshape(a, $pd, ngrp) : a
chk = rows(ret.b) + nelem(ret.a) - nreg
ret.drop = chk &lt; ngrp

return ret
</code>
</gretl-function>
<gretl-function name="ssr_by_unit" type="matrix" private="1">
 <params count="5">
  <param name="res" type="series" const="true"/>
  <param name="a" type="matrix" const="true"/>
  <param name="N" type="scalar"/>
  <param name="ngrp" type="scalar"/>
  <param name="timevar" type="bool"/>
 </params>
<code>/* -doc -
compute the ssr per unit for all possible groupings
*/

ssr_mat = zeros(N, ngrp)
if !timevar
  ng = rows(a) # should be equal to ngrp, but it may be not
  loop i = 1 .. ng
    tmp = pshrink(psum((res-a[i])^2))
    ssr_mat[,i] = tmp
  endloop
else
  loop i = 1 .. ngrp
    series tmp = mshape(a[,i], $nobs, 1)
    e = res - tmp
    ssr_mat[,i] = pshrink(psum(e^2))
  endloop
endif

return ssr_mat
</code>
</gretl-function>
<gretl-function name="assignment_step" type="matrix" private="1">
 <params count="5">
  <param name="res" type="series" const="true"/>
  <param name="a" type="matrix" const="true"/>
  <param name="N" type="scalar"/>
  <param name="ngrp" type="scalar"/>
  <param name="timevar" type="bool"/>
 </params>
<code>/* -doc-
Bonhomme-Manresa (2015) -- Assignment step: given the coefficients, assign the units to the various groups (also check that no group remains
empty
*/

ssr_mat = ssr_by_unit(res, a, N, ngrp, timevar)

# for each unit, find the group that minimises the ssr
matrix new = iminr(ssr_mat)
# sanity check
if rows(values(new)) == 1
  printf &quot;What???? ng = %d\n&quot;, ng
endif

return new
</code>
</gretl-function>
<gretl-function name="algo1_core" type="bundle" private="1">
 <params count="7">
  <param name="y" type="series" const="true"/>
  <param name="X_in" type="list"/>
  <param name="ngrp" type="scalar" default="4"/>
  <param name="timevar" type="bool" default="0"/>
  <param name="initgrp" type="matrix" optional="true" const="true"/>
  <param name="maxiter" type="scalar" default="1024"/>
  <param name="verbose" type="scalar" default="0"/>
 </params>
<code>/* -doc-
This function performs algorithm 1 with different group
initialisation: &quot;given&quot; expects an initial input
*/

N = $nobs/$pd            # number of units
bundle ret = _(N=N, parnames=varnames(X_in))

X = X_in - const
nreg = nelem(X)

bundle ret = ret + _(initgrp=initgrp, drop=0)

done = 0
iter = 0

# P2 is the smallest power of 2 strictly larger that $pd. For
# example, if $pd = 3, then P2 = 4; if $pd = 4, P2 = 8, etc.
# it is used with time-varying GFE to build interactions
# (unused with time-fixed effects)

scalar P2 = timevar ? 2^ceil(log2($pd+1)) : NA
grp = initgrp

loop while !done &amp;&amp; iter &lt; maxiter
  iter++
  bundle tmpbun = update_step(y, X, ngrp, timevar, grp, P2)
  if tmpbun.drop
    ret.drop = 1
    break
  else
    b = tmpbun.b
    a = tmpbun.a
    loglik = tmpbun.loglik
    obj = tmpbun.obj
  endif

  series res = y - lincomb(X, b)
  new = assignment_step(res, a, N, ngrp, timevar)

  # check if any individual has moved from one group to another

  eq = (grp .= new)'
  grp = new
  done = minr(eq)

  if verbose
    printf &quot;iter = %d, loglik = %g, &quot;, iter, loglik
    printf &quot;switchers = %d&quot;, N - sum(eq)
    printf &quot;\n&quot;
    flush
  endif

endloop

if ret.drop == 0
  ret.coeff = b
  ret.a     = a
  ret.nreg  = nreg
  # ret.iter  = iter
  ret.grp   = grp
  ret.lnl   = loglik
  ret.obj   = obj
endif

if verbose
  printf &quot;Time: %g (%3d iterations), llik = %12.5f\n&quot;, $stopwatch, iter, loglik
endif

return ret
</code>
</gretl-function>
<gretl-function name="algo1_estim" type="bundle" private="1">
 <params count="3">
  <param name="y" type="series" const="true"/>
  <param name="X_in" type="list"/>
  <param name="opts" type="bundle"/>
 </params>
<code>/* -doc-
performs estimation via algorithm 1
*/

X = X_in - const
T = $pd
N = $nobs/T

timevar = opts.tvar
ngrp = opts.ngrp
method = opts.method
verbose = opts.verbose

ret = _(opts=opts, N=N, T=T, X=X_in, depvarname=argname(y))

if method == &quot;random&quot;
  maxit = opts.randstarts
  bestcrit = $huge
  bundle best

  i = 0
  dropped = 0
  loop while i &lt; maxit
    inigrp = mrandgen(i, 1, ngrp, N, 1)
    b = algo1_core(y, X, ngrp, timevar, inigrp,, verbose &gt; 1)

    if b.drop == 1
      dropped++
    else
      i++
      if b.obj &lt; bestcrit
        bestcrit = b.obj
        best = b
        nbest = i
        if verbose
          printf &quot;\rmodel %4d: %15.8f\n&quot;, i, bestcrit
          flush
        endif
      endif
    endif
  endloop

  ret = ret + best
  ret.dropped = dropped
else
  b = algo1_core(y, X, ngrp, timevar, opts.inigrp,, verbose &gt; 1)
  ret = ret + b
endif

#    series ret.depvar = y
string ret.depvarname = argname(y)
list ret.X = X

return ret
</code>
</gretl-function>
<gretl-function name="add_sandwich" type="scalar" private="1">
 <params count="3">
  <param name="y" type="series" const="true"/>
  <param name="X" type="list"/>
  <param name="mod" type="bundleref"/>
 </params>
<code>scalar err = 0
matrix grp = mod.grp
scalar timevar = mod.opts.tvar
scalar P2 = timevar ? 2^ceil(log2($pd+1)) : NA
series id = $unit
scalar k = nelem(X)
series group_id = timevar ? (pexpand(grp-1)) * P2 + time : pexpand(grp)
ols y const X dummify(group_id) --cluster=id --quiet
mod.vcv = $vcv[2:k+1, 2:k+1]
mod.stderr = sqrt(diag(mod.vcv))
mod.bootrep = 0
return err
</code>
</gretl-function>
<gretl-function name="gfe_estimate_fixed" type="bundle" private="1">
 <params count="4">
  <param name="y" type="series" const="true"/>
  <param name="X" type="list"/>
  <param name="G" type="scalar"/>
  <param name="opts" type="bundle"/>
 </params>
<code>scalar N = $nobs/$pd
opts.ngrp = G
init_groups(y, X, N, &amp;opts)
scalar verbose = opts.verbose

if opts.algorithm == 2
  bundle GOAT = _(obj=$huge)
  scalar nmax = NA
  scalar timevar = opts.tvar
  scalar P2 = timevar ? 2^ceil(log2($pd+1)) : NA

  randstart = opts.randstarts

  if verbose
    string extra = opts.parallel == 0 ? &quot;single-thread&quot; : &quot;MPI-parallel&quot;
    printf &quot;Starting algorithm 2... (%s)\n&quot;, extra
    printf &quot;random starts = %d\n&quot;, randstart
    flush
  endif

  if opts.parallel == 0
    # single-threaded estimation
    loop outside_iter = 1 .. randstart
      best = algo2_estim(y, X, G, timevar, opts.inigrp, nmax)
      if verbose
        printf &quot;Random start %d, obj = %.6g (best so far = %.6g)\n&quot;, outside_iter, best.obj, GOAT.obj
        flush
      endif
      if best.obj &lt; GOAT.obj
        GOAT=best
      endif
    endloop

    opts.inigrp = GOAT.gamma
  else
    # rather arbitrary auto initialisation of realloc_max
    # if not user-given
    best = algo2_mpiblock(y, X, G, timevar, opts.parallel, nmax, randstart, verbose)
    opts.inigrp = best.gamma
  endif
  opts.method=&quot;given&quot; # temporary
endif

mod = algo1_estim(y, X, opts)

if opts.algorithm == 2
  opts.method=&quot;random&quot;
endif

mod.depvarname = argname(y)
return mod
</code>
</gretl-function>
<gretl-function name="panel_resample" type="series" private="1">
 <params count="4">
  <param name="x" type="series" const="true"/>
  <param name="N" type="scalar"/>
  <param name="T" type="scalar"/>
  <param name="resmat" type="matrix"/>
 </params>
<code>/* -doc-
needed for the bootstrap
*/

m = mshape({x}, T, N)
series ret = vec(m[,resmat])
return ret
</code>
</gretl-function>
<gretl-function name="add_boot_vcv" type="scalar" private="1">
 <params count="2">
  <param name="mod" type="bundleref"/>
  <param name="bootrep" type="scalar" default="128"/>
 </params>
<code>series y = mod.depvar
list X = mod.X

err = 0
scalar k = nelem(X)

matrix tgrp = mod.grp
scalar timevar = mod.tvar
scalar N = mod.N
scalar ngroups = mod.ngrp

matrix BB = mshape(NA, bootrep, k) # will hold the bootstrapped coefficients

scalar iter = 0
scalar good = 0
scalar dropped = 0
scalar maxiter = 2^12
scalar maxit_for_boot = 128
matrix lliks = zeros(bootrep,1)

bootopts = mod.opts
bootopts.method = &quot;random&quot;

bootopts.trials = maxit_for_boot
bootopts.verbose = 0
bootopts.algorithm = mod.algorithm

if bootopts.algorithm &gt; 1
  # common stuff for the two version of algorithm 2
  bundle GOAT = _(obj=$huge)
  scalar nmax = NA
  timevar = bootopts.tvar
  G = bootopts.ngrp
  verbose = bootopts.verbose
  randstart = 8

  if verbose
    printf &quot;Starting algorithm 2...\n\n&quot;
    flush
  endif
endif

printf &quot;Starting bootstrap iterations\n&quot;
flush

loop while (iter &lt; bootrep)
  iter++
  if iter%5 == 0
    printf &quot;boot %4d/%4d\r&quot;, iter, bootrep
    flush
  endif

  boot_draw = mrandgen(i, 1, N, 1, N)
  # resample the dep. var
  series by = panel_resample(y, N, $pd, boot_draw)
  # resample the explanatory variables
  list bX = empty
  loop foreach j X
    series b$j = panel_resample(X.$j, N, $pd, boot_draw)
    bX += b$j
  endloop

  # re-estimate

  init_groups(by, bX, N, &amp;bootopts)

  if bootopts.algorithm == 2
    loop outside_iter = 1 .. randstart
      best = algo2_estim(by, bX, G, timevar, bootopts.inigrp, nmax)
      if best.obj &lt; GOAT.obj
        GOAT=best
      endif
    endloop

    bootopts.method=&quot;given&quot;
    bootopts.inigrp = GOAT.gamma
  elif bootopts.algorithm == 3

    # rather arbitrary auto initialisation of realloc_max
    # if not user-given
    scalar neigh_max = ok(nmax) ? nmax : floor(sqrt(N))
    scalar j_max = 128
    scalar P2 = timevar ? 2^ceil(log2($pd+1)) : NA

    best = algo2_mpiblock(by, bX, G, timevar, nmax, randstart)

    bootopts.method = &quot;given&quot;
    bootopts.inigrp = best.gamma

  endif

  bb = algo1_estim(y, X, bootopts)

  # printf &quot;bb.loglik = %g\n&quot;, bb.lnl
  # printf &quot;coeff =\n%12.6f\n&quot;, bb.coeff'

  lliks[iter] = bb.lnl
  BB[iter,] = bb.coeff'
endloop

vcv = mcov(BB)
if 1
  bias = meanc(BB)' - mod.coeff
  vcv += bias * bias'
endif

mod.bootrep = bootrep
mod.vcv = vcv
mod.stderr = sqrt(diag(vcv))

return err
</code>
</gretl-function>
<gretl-function name="showfreq" type="void" private="1">
 <params count="1">
  <param name="grp" type="matrix"/>
 </params>
<code>frq = sumr(values(grp) .= grp')
rlab = &quot;Group &quot; ~ seq(1, rows(frq)) ~ &quot;:&quot;
rnameset(frq, rlab)
printf &quot;\n%4d&quot;, frq
flush
</code>
</gretl-function>
<gretl-function name="relocate" type="matrix" private="1">
 <params count="2">
  <param name="grp" type="matrix" const="true"/>
  <param name="n" type="scalar"/>
 </params>
<code>/* -doc-
here we take an intial group assignment (from 1 to ngrp)
and produce a new assignment where n units are switched
randomly to another group (modular artithmetic is used
for optimal perfomance)
*/

matrix ret = grp
scalar ngrp = max(grp)
scalar N = rows(grp)

# extract units without replacement
matrix tmp = seq(1,N)' ~ muniform(N,1)
matrix to_rep = msortby(tmp,2)[1:n,1]

# draw new group
matrix grep = grp[to_rep]
matrix shuffle = mrandgen(i, 1, ngrp-1, n, 1)
ret[to_rep] = ((grep + shuffle - 1) % ngrp) + 1
return ret
</code>
</gretl-function>
<gretl-function name="algo2_estim" type="bundle" private="1">
 <params count="6">
  <param name="y" type="series" const="true"/>
  <param name="X_in" type="list"/>
  <param name="G" type="scalar"/>
  <param name="timevar" type="bool"/>
  <param name="initgrp" type="matrix" optional="true" const="true"/>
  <param name="nmax" type="scalar" default="NA"/>
 </params>
<code>/* -doc-
Algorithm 2 by Bonhomme and Manresa (2015)
*/

scalar N = $nobs/$pd            # number of units
bundle ret = _(N=N, parnames=varnames(X_in), tvar=timevar, ngrp=G)

X = X_in - const
nreg = nelem(X)
# mX = {X}

# go with an initial grouping
matrix grp = initgrp
bundle ret = ret + _(initgrp=grp, drop=0)

# rather arbitrary auto initialisation of neigh_max
# if not user-given
scalar neigh_max = ok(nmax) ? nmax : floor(sqrt(N))
scalar j_max = 128
scalar P2 = timevar ? 2^ceil(log2($pd+1)) : NA

bundle best = _(obj=$huge)

is_start_ok = 0
loop while !is_start_ok
  matrix grp = mrandgen(i, 1, G, N, 1)
  bundle tmp = update_step(y, X, G, timevar, grp, P2)
  series res = y - lincomb(X, tmp.b)
  matrix gprime = assignment_step(res, tmp.a, N, G, timevar)
  is_start_ok = rows(values(gprime)) == G
endloop

loop j = 0 .. j_max
  n = 1
  loop while n &lt; neigh_max
    matrix gg = relocate(gprime, n)

    bundle tmp = algo1_core(y, X, G, timevar, gg)
    if tmp.drop
      continue
    endif

    series res = y - lincomb(X, tmp.coeff)
    matrix newgrp = tmp.grp
    matrix candidate = ssr_by_unit(res, tmp.a, N, G, timevar)
    scalar newmin = sumc(minr(candidate))

    if newmin &lt; best.obj
      # printf &quot;\tnewmin = %g (iter = %d)\n&quot;, newmin, j
      gprime = iminr(candidate)
      best.obj = newmin
      best.gamma = gprime
    else
      n++
    endif
    flush
  endloop
endloop

return best
</code>
</gretl-function>
<gretl-function name="starts_per_core" type="matrix" private="1">
 <params count="2">
  <param name="rands" type="scalar"/>
  <param name="n" type="scalar"/>
 </params>
<code>scalar h = floor(rands/n)
ret = mshape(h, 1, n)
top_up = rands - sum(ret)
if top_up &gt; 0
  ret[1:top_up] += 1
endif
return ret
</code>
</gretl-function>
<gretl-function name="algo2_mpiblock" type="bundle" private="1">
 <params count="8">
  <param name="y" type="series" const="true"/>
  <param name="X" type="list"/>
  <param name="G" type="scalar"/>
  <param name="timevar" type="scalar"/>
  <param name="ncores" type="scalar"/>
  <param name="nmax" type="scalar"/>
  <param name="randstarts" type="scalar"/>
  <param name="verbose" type="scalar"/>
 </params>
<code>err = 0

bundle to_mpi = _(G, timevar, verbose, nmax)
string to_mpi.inimeth = &quot;random&quot;
matrix to_mpi.Xl = X
matrix to_mpi.randstarts = randstarts
scalar to_mpi.seed = $seed
bwrite(to_mpi, &quot;parpass.xml&quot;, 1)

act_cores = ncores &gt; randstarts ? randstarts : ncores

mpi --send-functions --send-data --quiet --np=act_cores

          bundle from_outside = bread(&quot;parpass.xml&quot;, 1)
          scalar G = from_outside.G
          scalar timevar = from_outside.timevar
          scalar verbose = from_outside.verbose
          scalar nmax = from_outside.nmax
          scalar randstarts = from_outside.randstarts
          scalar seed = from_outside.seed

          string inimeth = from_outside.inimeth
          list X = from_outside.Xl

          my_seed = seed + 32*$mpirank
          set seed my_seed

          starts = starts_per_core(randstarts, $mpisize)
          local_starts = starts[$mpirank+1]

          bestcrit = $huge
          loop i = 1 .. local_starts
              bundle new = algo2_estim(y, X, G, timevar, nmax)
              if verbose &gt; 1
                  printf &quot;Process %d: start %d/%d, obj = %.6g\n&quot;, $mpirank, i, local_starts, new.obj
                  flush
              endif
              if new.obj &lt; bestcrit
                  bestcrit = new.obj
                  best = new
              endif
          endloop

          mpibarrier()
          if $mpirank &gt; 0
              mpisend(best, 0)
          else
              bundles mods = array($mpisize)
              mods[1] = best
              loop i = 2 .. $mpisize
                  mods[i] = mpirecv(i-1)
              endloop
          endif

          bestobj = $huge
          if $mpirank == 0
              if verbose
                  printf &quot;\n\n&quot;
              endif

              nbest = 1
              loop i = 1 .. $mpisize
                  if verbose
                      printf &quot;thread %03d, obj = %12.6f\n&quot;, i, mods[i].obj
                  endif

                  if mods[i].obj &lt; bestobj
                      nbest = i
                      bestobj = mods[i].obj
                  endif
              endloop
              bundle ret = mods[nbest]
              bwrite(ret, &quot;best.xml&quot;, 1)
          endif
      end mpi

  GOAT=bread(&quot;best.xml&quot;, 1)

  return GOAT
</code>
</gretl-function>
<sample-script>
set verbose off
include GFE.gfn
open abdata.gdt --quiet

set seed 8273647
list X = w k ys

### make panel balanced

list ALL = n X
smpl (YEAR &gt; 1976) --restrict  
series d = ok(ALL)
smpl pmin(d) == 1 --restrict

### do GFE estimation

nGrp = 6
opts = _(verbose = 1)

### uncomment below to enable BIC-based model selection
# opts.BICselect = 1

mod = gfe_estimate(n, X, nGrp, opts)
gfe_printout(mod)

### use algorithm 1 (should give a worse solution in terms of SSR)

opts.algorithm = 1
opts.randstarts = 2048
mod = gfe_estimate(n, X, nGrp, opts)
gfe_printout(mod)
</sample-script>
</gretl-function-package>
</gretl-functions>
