Hi all,

sorry, this is going to be long and a bit involved. While working on a package, I encountered some weirdness when creating new gretl list objects off of a $model coming from a GUI model window after doing OLS. I do have a stripped-down package test.gfn which I'm attaching for illustration.

* Technical aim here: Inside the GUI function (here: GUI_uniFCboot) which is run from the Analysis menu of the OLS model window, I want to look at the regressors $model.xlist and I want to focus only on those terms that are exogenous (not lagged endogenous, and also not the constant).

* Example:

1) Install somewhere the test.gfn package, attach it to the menu, load the denmark dataset, and in the GUI regress LRM on IBO, const, and two own lags.

2) Go to the new menu entry Analysis/testtesttest, choose horizon=2 (but that shouldn't matter) and hit OK.

3) I get my debug printout: "We shouldn't have any lags remaining in here: IBO,LRM_1,LRM_2", which obviously *does* contain the LRM lags.

* Background: In the function, I'm trying to create a sub-list by doing (where 'mod' is a copy of $model):

list Lexo = mod.xlist - lags(mod.maxlag, mod.ylist) - const # all but endo-lags and const

and then I'm printing out varname(Lexo), with the result above. Now I can theoretically imagine some reasons why my approach doesn't work, related to the list ID numbers inside bundles and functions and so on.

* HOWEVER, the real weirdness comes when I add/uncomment the following lines right before the Lexo creation, namely:

bundle br = rhslags($model) # especially this line seems to make a difference #  although it shouldn't!
print br.ylagnames
(The package version with these lines active is enclosed as test2.gfn.) -- And then everything works, i.e., there aren't any lagged endogenous terms left in the subsequent Lexo creation; result: "We shouldn't have any lags remaining in here: IBO" !

The point here is that the call to the private function rhslags() should be completely redundant and without any effect, shouldn't it? The return bundle br isn't used here, and there are no pointers involved. Instead it magically makes it so that everything falls into place, at least in this example.

What's behind all this? Some gretl bug? Or just further mystery with bundled series and lists? And concretely, how can I successfully remove from $model.xlist the lag terms in this context without doing black magic?

This is with gretl 2025a on Windows 11.

thanks a lot for reading until the end

sven
<?xml version="1.0" encoding="UTF-8"?>
<gretl-functions>
<gretl-function-package name="test" needs-time-series-data="true" model-requirement="ols" minver="2021b">
<author email="sven.schrei...@fu-berlin.de">Sven Schreiber</author>
<version>1.2</version>
<date>2025-04-05</date>
<description>Extensions for univariate forecast models</description>
<tags>C22 C53</tags>
<label>testtesttest</label>
<menu-attachment>MODELWIN/Analysis</menu-attachment>
<help>
test
</help>
<gretl-function name="uniFCboot" type="matrix">
 <params count="5">
  <param name="mod" type="bundle" const="true"/>
  <param name="H" type="int" min="1" default="1">
<description>horizon</description>
  </param>
  <param name="reps" type="int" min="1" default="2000">
<description>bootstrap draws</description>
  </param>
  <param name="quants" type="matrix" optional="true">
<description>evaluated quantiles</description>
  </param>
  <param name="exo" type="matrix" optional="true" const="true">
<description>future exog. influences</description>
  </param>
 </params>
<code>/* Returns a H x (1 + 2*Q) matrix of bootstrapped quantiles of
forecast (FC) densities;
'H' is the forecast horizon up to which the bootstrap is done.
The first column always refers to the median (0.5-quantile).

Q is the number of elements in 'quants', which should have values between 0 and 0.5.
The default for 'quants' is {0.005, 0.025, 0.05, 0.1}.
(Corresponding to two-sided 1%, 5%, 10%, 20%. Each value
is mirrored to the right: e.g. 0.1 together with 0.9.)

'exo' (Hx1) provides the future values of any exogenous terms
(other than the constant!) in the underlying equation (X'b, i.e.
already with the coefficients factored in). Otherwise
-- can pass null or {} as arg -- they are set to zero.

The bootstrap is based on resampling.
(Future possibilities:
- wild bootstrap, with flag in the bundle mod,)
*/

## pre-process the quantiles
if !exists(quants)
  matrix quants = {} # unified treatment
endif
quants = procquants(quants)

## pre-process the exogenous terms
if !exists(exo)
  matrix exo = {}
endif

if nelem(exo)
  matrix Xb = vec(exo)
  errorif( rows(Xb) != H, &quot;num of exo values must match horizon H&quot;)
else
  matrix Xb = zeros(H,1)
endif

## constant?
wconst = inlist(mod.xlist, const)
if wconst
  Xb += mod.coeff[1]	# const always comes first in $coeff
endif

# process the lag information
bundle mod2 = rhslags(mod)

# lag coefficients
lagorder = max(mod2.ylags)
matrix comptop = zeros(1, lagorder)
loop i = 1..rows(mod2.ylags)
  whichcf = mod2.ylagspos[i]
  comptop[1, mod2.ylags[i]] = mod.coeff[whichcf]
endloop

# initial values for the FC (last 'lagorder' values in-sample)
matrix init = { mod.ylist[1] }	# the dep var as vector
init = init[rows(init) - lagorder + 1 : ] # final lagorder values

## the bootstrap
matrix res = { mod.uhat }
matrix FCboot = zeros(H, 0)
loop d = 1..reps
  # resampling (non-wild so far...)
  matrix rndix = mrandgen(i, 1, rows(res), H, 1)
  matrix innov = res[rndix]

  FCboot ~= varsimul(comptop, Xb + innov, init)[lagorder + 1: ,]
endloop

# evaluate the distribution
matrix out = transp(quantile(FCboot', quants))
cnameset(out, sprintf(&quot;% g&quot;, 100*quants))
rnameset(out, sprintf(&quot;% d&quot;, seq(1,H)))
return out
</code>
</gretl-function>
<gretl-function name="GUI_uniFCboot" type="bundle" menu-only="1" pkg-role="gui-main">
 <params count="5">
  <param name="H" type="int" min="1" default="1">
<description>horizon</description>
  </param>
  <param name="reps" type="int" min="1" default="2000">
<description>bootstrap draws</description>
  </param>
  <param name="quants" type="matrix" optional="true">
<description>non-standard quantiles</description>
  </param>
  <param name="alpha" type="scalar" min="0" max="1" default="0.5">
<description>Linlin only: asymmetry param</description>
  </param>
  <param name="exo" type="matrix" optional="true">
<description>future exog. influences</description>
  </param>
 </params>
<code>bundle mod = $model # copy the active model (from GUI model context)

# check and warn if exogenous terms
/*
list endolags = lags(mod.maxlag, mod.ylist)
list endolags print
matrix elnumbers = lags(mod.maxlag, mod.ylist)
print elnumbers

matrix xlistnumbers = mod.xlist
print xlistnumbers

bundle br = rhslags($model) # especially this line seems to make a difference
#   although it shouldn't!
print br.ylagnames

list checko = mod.xlist &amp;&amp; lags(mod.maxlag, mod.ylist)
matrix checkonums = checko
print checkonums
*/
print &quot;------&quot;

list Lexo = mod.xlist - lags(mod.maxlag, mod.ylist) - const # all but endo-lags and const
if nelem(Lexo)
  printf &quot;We shouldn't have any lags remaining in here: %s\n&quot;, varname(Lexo)
endif

# pre-process optional args
if !exists(quants)
  matrix quants = {}
endif
if !exists(exo)
  matrix exo = {}
endif

if alpha != 0.5	# we do lin-lin point FC
  print &quot;test; do nothing&quot;

else	# intervals for quantiles

  matrix temp = uniFCboot(mod,H,reps,quants,exo)

  # add result to bundle
  matrix mod.uniFCboot = temp

  printf &quot;Bootstrapped forecasts for %s, up to step %d,\n&quot;, varnames(mod.ylist)[1], H
  printf &quot; with %d replications,\n&quot;, reps
  printf &quot; starting from sample endpoint %s.\n&quot;, obslabel($t2)
  printf &quot;Chosen quantiles (plus right-tail analogues): % g\n&quot;, procquants(quants)
  print temp
endif

return mod
</code>
</gretl-function>
<gretl-function name="rhslags" type="bundle" private="1">
 <params count="1">
  <param name="mod" type="bundle" const="true"/>
 </params>
<code># (private function)
/* This function expects an input bundle of the type
that is provided by gretl's $model accessor.

It puts the information about the names of the
appearing lagged terms (ylagnames, strings array), which lags are used (ylags, matrix), and which is
their respective position in the regressor list
(ylagspos, matrix) into the returned bundle.

This only works if (a) the lagged terms are exactly
named as gretl's lags() function does it, (b) if
the ordering is strictly ascending (e.g. -1 first).
There can be gaps in the lag structure.
*/

bundle out = mod # copy

# create the max potential number of lags
list templags = lags(nelem(mod.xlist), mod.ylist)
# keep those lags that were actually used in $xlist
list sec = mod.xlist &amp;&amp; templags
# and record their names
strings out.ylagnames = varnames(sec)

# determine which lags and where they appear
matrix out.ylags = {}
matrix out.ylagspos = {}
loop foreach s sec
  out.ylags |= inlist(templags, sec.$s) # i-th pos in templags is lag
  out.ylagspos |= inlist(mod.xlist, sec.$s) # where in $xlist/$coef ?
endloop

return out
</code>
</gretl-function>
<gretl-function name="standardquants" type="matrix" private="1">
<code>return {0.005, 0.025, 0.05, 0.1}
</code>
</gretl-function>
<gretl-function name="procquants" type="matrix" private="1">
 <params count="1">
  <param name="quants" type="matrix" optional="true"/>
 </params>
<code>if !exists(quants)
  matrix quants = {} # for unified treatment
endif

if nelem(quants)
  matrix q = sort(vec(quants))'

  errorif( min(q) &lt;= 0 || max(q) &gt;= 1, &quot;invalid input for quants&quot; )

else
  matrix q = standardquants()
endif
# add the median
q = 0.5 ~ q ~ mreverse(1 - q')'

return q
</code>
</gretl-function>
<sample-script>
# Sample script for the uniFCextensions package for gretl

clear
include test.gfn --force

###################
#
# Initial example, pure AR equation

open denmark 
H = 3

### test test
</sample-script>
</gretl-function-package>
</gretl-functions>
<?xml version="1.0" encoding="UTF-8"?>
<gretl-functions>
<gretl-function-package name="test" needs-time-series-data="true" model-requirement="ols" minver="2021b">
<author email="sven.schrei...@fu-berlin.de">Sven Schreiber</author>
<version>1.2</version>
<date>2025-04-05</date>
<description>Extensions for univariate forecast models</description>
<tags>C22 C53</tags>
<label>testtesttest</label>
<menu-attachment>MODELWIN/Analysis</menu-attachment>
<help>
test
</help>
<gretl-function name="uniFCboot" type="matrix">
 <params count="5">
  <param name="mod" type="bundle" const="true"/>
  <param name="H" type="int" min="1" default="1">
<description>horizon</description>
  </param>
  <param name="reps" type="int" min="1" default="2000">
<description>bootstrap draws</description>
  </param>
  <param name="quants" type="matrix" optional="true">
<description>evaluated quantiles</description>
  </param>
  <param name="exo" type="matrix" optional="true" const="true">
<description>future exog. influences</description>
  </param>
 </params>
<code>/* Returns a H x (1 + 2*Q) matrix of bootstrapped quantiles of
forecast (FC) densities;
'H' is the forecast horizon up to which the bootstrap is done.
The first column always refers to the median (0.5-quantile).

Q is the number of elements in 'quants', which should have values between 0 and 0.5.
The default for 'quants' is {0.005, 0.025, 0.05, 0.1}.
(Corresponding to two-sided 1%, 5%, 10%, 20%. Each value
is mirrored to the right: e.g. 0.1 together with 0.9.)

'exo' (Hx1) provides the future values of any exogenous terms
(other than the constant!) in the underlying equation (X'b, i.e.
already with the coefficients factored in). Otherwise
-- can pass null or {} as arg -- they are set to zero.

The bootstrap is based on resampling.
(Future possibilities:
- wild bootstrap, with flag in the bundle mod,)
*/

## pre-process the quantiles
if !exists(quants)
  matrix quants = {} # unified treatment
endif
quants = procquants(quants)

## pre-process the exogenous terms
if !exists(exo)
  matrix exo = {}
endif

if nelem(exo)
  matrix Xb = vec(exo)
  errorif( rows(Xb) != H, &quot;num of exo values must match horizon H&quot;)
else
  matrix Xb = zeros(H,1)
endif

## constant?
wconst = inlist(mod.xlist, const)
if wconst
  Xb += mod.coeff[1]	# const always comes first in $coeff
endif

# process the lag information
bundle mod2 = rhslags(mod)

# lag coefficients
lagorder = max(mod2.ylags)
matrix comptop = zeros(1, lagorder)
loop i = 1..rows(mod2.ylags)
  whichcf = mod2.ylagspos[i]
  comptop[1, mod2.ylags[i]] = mod.coeff[whichcf]
endloop

# initial values for the FC (last 'lagorder' values in-sample)
matrix init = { mod.ylist[1] }	# the dep var as vector
init = init[rows(init) - lagorder + 1 : ] # final lagorder values

## the bootstrap
matrix res = { mod.uhat }
matrix FCboot = zeros(H, 0)
loop d = 1..reps
  # resampling (non-wild so far...)
  matrix rndix = mrandgen(i, 1, rows(res), H, 1)
  matrix innov = res[rndix]

  FCboot ~= varsimul(comptop, Xb + innov, init)[lagorder + 1: ,]
endloop

# evaluate the distribution
matrix out = transp(quantile(FCboot', quants))
cnameset(out, sprintf(&quot;% g&quot;, 100*quants))
rnameset(out, sprintf(&quot;% d&quot;, seq(1,H)))
return out
</code>
</gretl-function>
<gretl-function name="GUI_uniFCboot" type="bundle" menu-only="1" pkg-role="gui-main">
 <params count="5">
  <param name="H" type="int" min="1" default="1">
<description>horizon</description>
  </param>
  <param name="reps" type="int" min="1" default="2000">
<description>bootstrap draws</description>
  </param>
  <param name="quants" type="matrix" optional="true">
<description>non-standard quantiles</description>
  </param>
  <param name="alpha" type="scalar" min="0" max="1" default="0.5">
<description>Linlin only: asymmetry param</description>
  </param>
  <param name="exo" type="matrix" optional="true">
<description>future exog. influences</description>
  </param>
 </params>
<code>bundle mod = $model # copy the active model (from GUI model context)

# check and warn if exogenous terms
/*
list endolags = lags(mod.maxlag, mod.ylist)
list endolags print
matrix elnumbers = lags(mod.maxlag, mod.ylist)
print elnumbers

matrix xlistnumbers = mod.xlist
print xlistnumbers
*/

bundle br = rhslags($model) # especially this line seems to make a difference
#   although it shouldn't!
print br.ylagnames

/*
list checko = mod.xlist &amp;&amp; lags(mod.maxlag, mod.ylist)
matrix checkonums = checko
print checkonums
*/
print &quot;------&quot;

list Lexo = mod.xlist - lags(mod.maxlag, mod.ylist) - const # all but endo-lags and const
if nelem(Lexo)
  printf &quot;We shouldn't have any lags remaining in here: %s\n&quot;, varname(Lexo)
endif

# pre-process optional args
if !exists(quants)
  matrix quants = {}
endif
if !exists(exo)
  matrix exo = {}
endif

if alpha != 0.5	# we do lin-lin point FC
  print &quot;test; do nothing&quot;

else	# intervals for quantiles

  matrix temp = uniFCboot(mod,H,reps,quants,exo)

  # add result to bundle
  matrix mod.uniFCboot = temp

  printf &quot;Bootstrapped forecasts for %s, up to step %d,\n&quot;, varnames(mod.ylist)[1], H
  printf &quot; with %d replications,\n&quot;, reps
  printf &quot; starting from sample endpoint %s.\n&quot;, obslabel($t2)
  printf &quot;Chosen quantiles (plus right-tail analogues): % g\n&quot;, procquants(quants)
  print temp
endif

return mod
</code>
</gretl-function>
<gretl-function name="rhslags" type="bundle" private="1">
 <params count="1">
  <param name="mod" type="bundle" const="true"/>
 </params>
<code># (private function)
/* This function expects an input bundle of the type
that is provided by gretl's $model accessor.

It puts the information about the names of the
appearing lagged terms (ylagnames, strings array), which lags are used (ylags, matrix), and which is
their respective position in the regressor list
(ylagspos, matrix) into the returned bundle.

This only works if (a) the lagged terms are exactly
named as gretl's lags() function does it, (b) if
the ordering is strictly ascending (e.g. -1 first).
There can be gaps in the lag structure.
*/

bundle out = mod # copy

# create the max potential number of lags
list templags = lags(nelem(mod.xlist), mod.ylist)
# keep those lags that were actually used in $xlist
list sec = mod.xlist &amp;&amp; templags
# and record their names
strings out.ylagnames = varnames(sec)

# determine which lags and where they appear
matrix out.ylags = {}
matrix out.ylagspos = {}
loop foreach s sec
  out.ylags |= inlist(templags, sec.$s) # i-th pos in templags is lag
  out.ylagspos |= inlist(mod.xlist, sec.$s) # where in $xlist/$coef ?
endloop

return out
</code>
</gretl-function>
<gretl-function name="standardquants" type="matrix" private="1">
<code>return {0.005, 0.025, 0.05, 0.1}
</code>
</gretl-function>
<gretl-function name="procquants" type="matrix" private="1">
 <params count="1">
  <param name="quants" type="matrix" optional="true"/>
 </params>
<code>if !exists(quants)
  matrix quants = {} # for unified treatment
endif

if nelem(quants)
  matrix q = sort(vec(quants))'

  errorif( min(q) &lt;= 0 || max(q) &gt;= 1, &quot;invalid input for quants&quot; )

else
  matrix q = standardquants()
endif
# add the median
q = 0.5 ~ q ~ mreverse(1 - q')'

return q
</code>
</gretl-function>
<sample-script>
# Sample script for the uniFCextensions package for gretl

clear
include test.gfn --force

###################
#
# Initial example, pure AR equation

open denmark 
H = 3

### test test
</sample-script>
</gretl-function-package>
</gretl-functions>
_______________________________________________
Gretl-devel mailing list -- gretl-devel@gretlml.univpm.it
To unsubscribe send an email to gretl-devel-le...@gretlml.univpm.it
Website: 
https://gretlml.univpm.it/postorius/lists/gretl-devel.gretlml.univpm.it/

Reply via email to