From ebc14b02bcb252a949d7e1a1bc7a4be6f56d5b32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Tue, 11 Mar 2025 17:30:34 +0100
Subject: [PATCH] =?UTF-8?q?Use=20MATLAB=20builtins=20=E2=80=9Cheight?=
 =?UTF-8?q?=E2=80=9D=20and=20=E2=80=9Cwidth=E2=80=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Since R2013b, MATLAB provides builtins “height” (resp. “width”) for computing
the number of rows (resp. columns) of a matrix.

Octave has been providing “rows” and “columns” for the same purpose for the
long time. For MATLAB compatibility, it introduced “height” and “width” in
version 10, so let’s standardize on MATLAB names.
---
 src/@dseries/fill_.m                          |  6 +++---
 src/@dseries/nobs.m                           |  4 ++--
 src/@dseries/projection.m                     |  4 ++--
 src/@dseries/subsasgn.m                       | 20 +++++++++----------
 src/@dseries/subsref.m                        | 14 ++++++-------
 src/@dseries/vobs.m                           |  4 ++--
 src/@x13/run.m                                | 14 ++++++-------
 src/initialize_dseries_class.m                | 14 +++++++++----
 .../{dims/columns.m => height/height.m}       |  8 ++++----
 .../missing/{dims/rows.m => width/width.m}    |  8 ++++----
 .../op/add_periods_to_array_of_dates.m        |  4 ++--
 11 files changed, 53 insertions(+), 47 deletions(-)
 rename src/utilities/missing/{dims/columns.m => height/height.m} (83%)
 rename src/utilities/missing/{dims/rows.m => width/width.m} (83%)

diff --git a/src/@dseries/fill_.m b/src/@dseries/fill_.m
index b7d7aa4..4cf8809 100644
--- a/src/@dseries/fill_.m
+++ b/src/@dseries/fill_.m
@@ -7,7 +7,7 @@ function o = fill_(o, name, value)
 % - name     [char, cell]    row char arry or cell of row char arrays.
 % - value    [double]        scalar, vector or matrix.
 
-% Copyright © 2023 Dynare Team
+% Copyright © 2023-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -28,7 +28,7 @@ if ischar(name)
     name = {name};
 end
 
-if iscell(name) & (rows(name)==1 || columns(name)==1)
+if iscell(name) & (height(name)==1 || width(name)==1)
     for  i=1:length(name)
         id = find(strcmp(name{i}, o.name));
         if isempty(id)
@@ -38,7 +38,7 @@ if iscell(name) & (rows(name)==1 || columns(name)==1)
                 o.data(:,id) = value;
             elseif isvector(value) && length(value)==length(name)
                 o.data(:,id) = value(i);
-            elseif ismatrix(value) && columns(value)==length(name) && rows(value)==nobs(o)
+            elseif ismatrix(value) && width(value)==length(name) && height(value)==nobs(o)
                 o.data(:,id) = value(:,i);
             else
                 error('dseries::fill: dimension of the last argument is not correct.')
diff --git a/src/@dseries/nobs.m b/src/@dseries/nobs.m
index 6779317..e34e523 100644
--- a/src/@dseries/nobs.m
+++ b/src/@dseries/nobs.m
@@ -2,7 +2,7 @@ function s = nobs(o)
 
 % Returns the number of observations in a @dseries object.
 
-% Copyright © 2014-2017 Dynare Team
+% Copyright © 2014-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -19,4 +19,4 @@ function s = nobs(o)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <https://www.gnu.org/licenses/>.
 
-s = rows(o.data);
\ No newline at end of file
+s = height(o.data);
diff --git a/src/@dseries/projection.m b/src/@dseries/projection.m
index 520361e..0341ca3 100644
--- a/src/@dseries/projection.m
+++ b/src/@dseries/projection.m
@@ -31,7 +31,7 @@ function o = projection(o, info, periods)
 %     or 'AR' with an autoregressive parameter equal to one (random walk).
 % [4] This projection routine only deals with exponential trends.
 
-% Copyright © 2022-2023 Dynare Team
+% Copyright © 2022-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -57,7 +57,7 @@ T = nobs(o);
 o.data = cat(1, o.data, zeros(periods, vobs(o)));
 o.dates = [o.dates; o.dates(end)+1:o.dates(end)+periods];
 
-for i=1:rows(INFO)
+for i=1:height(INFO)
     j = find(strcmp(o.name, INFO{i,1}));
     switch INFO{i,2}
       case 'Constant'
diff --git a/src/@dseries/subsasgn.m b/src/@dseries/subsasgn.m
index e4a9dcc..e6b6184 100644
--- a/src/@dseries/subsasgn.m
+++ b/src/@dseries/subsasgn.m
@@ -8,7 +8,7 @@ function A = subsasgn(A,S,B)
 %! @end deftypefn
 %@eod:
 
-% Copyright © 2012-2023 Dynare Team
+% Copyright © 2012-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -137,8 +137,8 @@ switch length(S)
                 merge_dseries_objects = false;
             elseif isnumeric(B)
                 merge_dseries_objects = false;
-                if isequal(length(tdx),rows(B))
-                    if isequal(columns(A.data),columns(B))
+                if isequal(length(tdx),height(B))
+                    if isequal(width(A.data),width(B))
                         A.data(tdx,:) = B;
                     else
                         error('dseries::subsasgn: Dimension error! The number of variables on the left and right hand side must match.')
@@ -163,7 +163,7 @@ switch length(S)
                 else
                     init = A.dates(1);
                 end
-                A.dates = init:(init+rows(B)-1);
+                A.dates = init:(init+height(B)-1);
             elseif isdseries(B)
                 A.data = B.data;
                 A.name = B.name;
@@ -185,7 +185,7 @@ switch length(S)
         else
             sA = extract(A,S(1).subs);
         end
-        if (isdseries(B) && isequal(vobs(sA), vobs(B))) || (isnumeric(B) && isequal(vobs(sA),columns(B))) || (isnumeric(B) && isequal(columns(B),1))
+        if (isdseries(B) && isequal(vobs(sA), vobs(B))) || (isnumeric(B) && isequal(vobs(sA),width(B))) || (isnumeric(B) && isequal(width(B),1))
             if isdates(S(2).subs{1})
                 [~, tdx] = intersect(sA.dates.time,S(2).subs{1}.time,'rows');
                 if isdseries(B)
@@ -196,18 +196,18 @@ switch length(S)
                     sA.data(tdx,:) = B.data(tdy,:);
                 elseif isnumeric(B)
                     merge_dseries_objects = false;
-                    if isequal(length(tdx),rows(B))
-                        if isequal(columns(sA.data),columns(B))
+                    if isequal(length(tdx),height(B))
+                        if isequal(width(sA.data),width(B))
                             sA.data(tdx,:) = B;
                         elseif isequal(size(B,2),1)
-                            sA.data(tdx,:) = repmat(B,1,columns(sA.data));
+                            sA.data(tdx,:) = repmat(B,1,width(sA.data));
                         else
                             error('dseries::subsasgn: Dimension error! The number of variables on the left and right hand side must match.')
                         end
                     else
-                        if isequal(columns(sA.data),columns(B)) && isequal(rows(B),1)
+                        if isequal(width(sA.data),width(B)) && isequal(height(B),1)
                             sA.data(tdx,:) = repmat(B,length(tdx),1);
-                        elseif isequal(rows(B),1)
+                        elseif isequal(height(B),1)
                             sA.data(tdx,:) = B;
                         else
                             error('dseries::subsassgn: Dimension error! The number of periods on the left and right hand side must match.')
diff --git a/src/@dseries/subsref.m b/src/@dseries/subsref.m
index dd971c3..884f51c 100644
--- a/src/@dseries/subsref.m
+++ b/src/@dseries/subsref.m
@@ -15,7 +15,7 @@ function r = subsref(o, S)
 %                     by applying a public method on `o`, or a dseries object built by extracting
 %                     a variable from `o`, or a dseries object containing a subsample.
 
-% Copyright © 2011-2023 Dynare Team
+% Copyright © 2011-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -42,10 +42,10 @@ switch S(1).type
         r = builtin('subsref', o, S(1));
       case 'nobs'
         % Returns the number of observations.
-        r = rows(o.data);
+        r = height(o.data);
       case 'vobs'
         % Returns the number of variables.
-        r = columns(o.data);
+        r = width(o.data);
       case 'init'
         % Returns a dates object (first date).
         r = o.dates(1);
@@ -271,16 +271,16 @@ switch S(1).type
             % Populate an empty dseries object.
             if isempty(o.dates)
                 r = copy(o);
-                r.dates = dates('1Y'):dates('1Y')+(rows(S(1).subs{1})-1);
+                r.dates = dates('1Y'):dates('1Y')+(height(S(1).subs{1})-1);
                 r.data = S(1).subs{1};
-                r.name = default_name(columns(r.data));
+                r.name = default_name(width(r.data));
                 r.tex = name2tex(r.name);
                 r.ops = cell(length(r.name), 1);
             else
                 r = copy(o);
-                r.dates = r.dates:r.dates+(rows(S(1).subs{1})-1);
+                r.dates = r.dates:r.dates+(height(S(1).subs{1})-1);
                 r.data = S(1).subs{1};
-                r.name = default_name(columns(r.data));
+                r.name = default_name(width(r.data));
                 r.tex = name2tex(r.name);
                 r.ops = cell(length(r.name), 1);
             end
diff --git a/src/@dseries/vobs.m b/src/@dseries/vobs.m
index 8188793..ab9afd7 100644
--- a/src/@dseries/vobs.m
+++ b/src/@dseries/vobs.m
@@ -8,7 +8,7 @@ function s = vobs(o)
 % OUTPUTS
 % - s   [integer]  scalar, number of variables in o.
 
-% Copyright © 2014-2017 Dynare Team
+% Copyright © 2014-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -25,4 +25,4 @@ function s = vobs(o)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <https://www.gnu.org/licenses/>.
 
-s = columns(o.data);
\ No newline at end of file
+s = width(o.data);
diff --git a/src/@x13/run.m b/src/@x13/run.m
index 33f7168..ec5b399 100644
--- a/src/@x13/run.m
+++ b/src/@x13/run.m
@@ -2,7 +2,7 @@ function run(o, basename)
 
 % Runs x13 program and saves results.
 
-% Copyright © 2017, 2022 Dynare Team
+% Copyright © 2017-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -345,12 +345,12 @@ if ~all(cellfun(@isempty, struct2cell(o.estimate)))
                         header = strjoin(tmp.textdata(1,1));
                         header = strsplit(header, {'\t'});
                         info   = tmp.textdata(3:end,1:2);
-                        for j = 1:rows(data)
-                            for k = 1:columns(info)
+                        for j = 1:height(data)
+                            for k = 1:width(info)
                                 o.results.(savedoutput{i}).(['root_' num2str(j)]).(header{k}) = strjoin(info(j,k));
                             end
-                            for k = 1:columns(data)
-                                o.results.(savedoutput{i}).(['root_' num2str(j)]).(header{k+columns(info)}) = data(j,k);
+                            for k = 1:width(data)
+                                o.results.(savedoutput{i}).(['root_' num2str(j)]).(header{k+width(info)}) = data(j,k);
                             end
                         end
                     elseif lower(savedoutput{i}) == 'itr'
@@ -358,8 +358,8 @@ if ~all(cellfun(@isempty, struct2cell(o.estimate)))
                         header = strjoin(tmp.textdata(1,1));
                         header = strsplit(header, {'\t'});
                         header = header(3:end-1);
-                        for j = 1:rows(data)
-                            for k = 1:columns(header)
+                        for j = 1:height(data)
+                            for k = 1:width(header)
                                 o.results.(savedoutput{i}).(['iter_' num2str(j)]).(header{k}) = data(j,k);
                             end
                         end
diff --git a/src/initialize_dseries_class.m b/src/initialize_dseries_class.m
index be66384..df799dc 100644
--- a/src/initialize_dseries_class.m
+++ b/src/initialize_dseries_class.m
@@ -1,6 +1,6 @@
 function initialize_dseries_class()
 
-% Copyright © 2015-2023 Dynare Team
+% Copyright © 2015-2025 Dynare Team
 %
 % This code is free software: you can redistribute it and/or modify
 % it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@ dseries_src_root = strrep(which('initialize_dseries_class'), 'initialize_dseries
 
 % Is the dseries package used as a standalone?
 dseries_src_path_s = strsplit(dseries_src_root, filesep());
-isstandalone = ~isequal(dseries_src_path_s(end-3:end), {'matlab', 'modules', 'dseries', 'src'}) & isempty(which('dynare'));
+isstandalone = ~isequal(dseries_src_path_s(end-2:end), {'matlab', 'dseries', 'src'}) & isempty(which('dynare'));
 
 % Set the subfolders to be added in the path.
 p = {'mdbnomics2dseries'; ...
@@ -70,8 +70,14 @@ if ~exist('ndim','file')
     p{end+1} = 'utilities/missing/ndim';
 end
 
-if ~exist('OCTAVE_VERSION', 'builtin') && isstandalone
-    p{end+1} = 'utilities/missing/dims';
+% “height” has been added in Octave version 10
+if exist('OCTAVE_VERSION', 'builtin') && ~exist('height', 'builtin') && isstandalone
+    p{end+1} = 'utilities/missing/height';
+end
+
+% “width” has been added in Octave version 10
+if exist('OCTAVE_VERSION', 'builtin') && ~exist('width', 'builtin') && isstandalone
+    p{end+1} = 'utilities/missing/width';
 end
 
 if ~exist('sample_hp_filter','file')
diff --git a/src/utilities/missing/dims/columns.m b/src/utilities/missing/height/height.m
similarity index 83%
rename from src/utilities/missing/dims/columns.m
rename to src/utilities/missing/height/height.m
index 6dc3568..12e3a22 100644
--- a/src/utilities/missing/dims/columns.m
+++ b/src/utilities/missing/height/height.m
@@ -1,8 +1,8 @@
-function c = columns(M)
+function r = height(x)
 
-% Computes the number of columns of a matrix
+% Computes the number of rows of a matrix, for Octave < 10
 
-% Copyright © 2005-2014 Dynare Team
+% Copyright © 2025 Dynare Team
 %
 % This code is free software: you can redistribute it and/or modify
 % it under the terms of the GNU General Public License as published by
@@ -17,4 +17,4 @@ function c = columns(M)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <https://www.gnu.org/licenses/>.
 
-c = size(M,2);
\ No newline at end of file
+r = rows(x);
diff --git a/src/utilities/missing/dims/rows.m b/src/utilities/missing/width/width.m
similarity index 83%
rename from src/utilities/missing/dims/rows.m
rename to src/utilities/missing/width/width.m
index 77210e4..d8c1770 100644
--- a/src/utilities/missing/dims/rows.m
+++ b/src/utilities/missing/width/width.m
@@ -1,8 +1,8 @@
-function r = rows(x)
+function c = width(M)
 
-% Computes the number of rows of a matrix
+% Computes the number of columns of a matrix, for Octave < 10
 
-% Copyright © 2005-2014 Dynare Team
+% Copyright © 2025 Dynare Team
 %
 % This code is free software: you can redistribute it and/or modify
 % it under the terms of the GNU General Public License as published by
@@ -17,4 +17,4 @@ function r = rows(x)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <https://www.gnu.org/licenses/>.
 
-r = size(x,1);
+c = width(M);
diff --git a/src/utilities/op/add_periods_to_array_of_dates.m b/src/utilities/op/add_periods_to_array_of_dates.m
index eba7cd9..6626fcd 100644
--- a/src/utilities/op/add_periods_to_array_of_dates.m
+++ b/src/utilities/op/add_periods_to_array_of_dates.m
@@ -2,7 +2,7 @@ function time = add_periods_to_array_of_dates(time, freq, p)
 
 % Adds a p periods (p can be negative) to a date (or a set of dates) characterized by array time and frequency freq.
 
-% Copyright © 2013-2023 Dynare Team
+% Copyright © 2013-2025 Dynare Team
 %
 % This file is part of Dynare.
 %
@@ -19,7 +19,7 @@ function time = add_periods_to_array_of_dates(time, freq, p)
 % You should have received a copy of the GNU General Public License
 % along with Dynare.  If not, see <https://www.gnu.org/licenses/>.
 
-if isequal(rows(time),1) && length(p)>1
+if isequal(height(time),1) && length(p)>1
     time = repmat(time,length(p),1);
 end
 
-- 
GitLab