1classdef dseries<handle % --*-- Unitary tests --*-- 2 3% Class for time series. 4 5% Copyright (C) 2013-2019 Dynare Team 6% 7% This code is free software: you can redistribute it and/or modify 8% it under the terms of the GNU General Public License as published by 9% the Free Software Foundation, either version 3 of the License, or 10% (at your option) any later version. 11% 12% Dynare dseries submodule is distributed in the hope that it will be useful, 13% but WITHOUT ANY WARRANTY; without even the implied warranty of 14% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15% GNU General Public License for more details. 16% 17% You should have received a copy of the GNU General Public License 18% along with Dynare. If not, see <http://www.gnu.org/licenses/>. 19 20properties 21 data = []; % Array of data (a column per variable, a row per observation) 22 name = {}; % Names of the variables. 23 tex = {}; % TeX names of the variables. 24 dates = dates(); % Dates associated to the observations. 25 ops = {}; % History of operations on the variables. 26 tags = struct(); % User defined tags on the variables. 27end 28 29methods 30 function o = dseries(varargin) 31 % Constructor for the dseries class 32 % 33 % INPUTS 34 % 35 % - If no input arguments, the constructore returns an empty dseries object. 36 % 37 % - If only one input argument is provided, the behaviour of the constructor depends on the type of the argument: 38 % + varargin{1} [dates] Constructor will return a dseries object without data. The dseries object can be populated later using dseries' methods. 39 % + varargin{1} [char] The name of a csv, m, mat or xlsx file containing data. A dseries object is created from these data. 40 % + varargin{1} [double] A T*N array of data. A dseries object is created from the array (T observations, N variables). 41 % 42 % - If only one two, three or four arguments are provided, we must have: 43 % + varargin{1} [double] A T*N array of data. 44 % + varargin{2} [dates, char] A single element dates object or a string representing a date, the initial date of the database. 45 % + varargin{3} [cell] A N*1 cell of char or a N*q array of char, the names of the variables. 46 % + varargin{4} [cell] A N*1 cell of char or a N*q array of char, the TeX names of the variables. 47 % 48 % OUTPUTS 49 % - o [dseries] 50 switch nargin 51 case 0 52 % Return empty object. 53 return 54 case 1 55 if isdates(varargin{1}) 56 switch length(varargin{1}) 57 case 0 58 error('dseries:WrongInputArguments', 'Input (identified as a dates object) must be non empty!'); 59 case 1 60 % Create an empty dseries object with an initial date. 61 o.dates = varargin{1}; 62 otherwise 63 error('dseries:WrongInputArguments', 'Input (identified as a dates object) must have a unique element!'); 64 end 65 return 66 elseif ischar(varargin{1}) 67 [init, o.data, o.name, o.tex, o.ops, o.tags] = load_data(varargin{1}); 68 o.dates = init:init+(nobs(o)-1); 69 elseif ~isoctave() && ~matlab_ver_less_than('8.2') && istable(varargin{1}) 70 % It is assumed that the dates are in the first column. 71 o.name = varargin{1}.Properties.VariableNames(2:end); 72 o.tex = name2tex(o.name); 73 o.data = varargin{1}{:,2:end}; 74 o.dates = dates(varargin{1}{1,1}{1})+(0:size(varargin{1}, 1)-1); 75 o.ops = cell(length(o.name), 1); 76 elseif isnumeric(varargin{1}) && isequal(ndims(varargin{1}),2) 77 o.data = varargin{1}; 78 o.name = default_name(vobs(o)); 79 o.tex = name2tex(o.name); 80 o.dates = dates(1,1):dates(1,1)+(nobs(o)-1); 81 o.ops = cell(length(o.name), 1); 82 elseif isstruct(varargin{1}) 83 o = struct2dseries(varargin{1}); 84 end 85 case {2,3,4} 86 if isequal(nargin,2) && ischar(varargin{1}) && isdates(varargin{2}) 87 % Instantiate dseries object with a data file and force the initial date to 88 % be as given by the second input argument (initial period represented 89 % with a dates object). 90 [~, o.data, o.name, o.tex, o.ops, o.tags] = load_data(varargin{1}); 91 o.dates = varargin{2}:varargin{2}+(nobs(o)-1); 92 return 93 end 94 if isequal(nargin,2) && ischar(varargin{1}) && ischar(varargin{2}) && isdate(varargin{2}) 95 % Instantiate dseries object with a data file and force the initial date to 96 % be as given by the second input argument (initial period represented with a 97 % string). 98 [~, o.data, o.name, o.tex, o.ops, o.tags] = load_data(varargin{1}); 99 o.dates = dates(varargin{2}):dates(varargin{2})+(nobs(o)-1); 100 return 101 end 102 a = varargin{1}; 103 b = varargin{2}; 104 if nargin<4 105 d = {}; 106 else 107 d = varargin{4}; 108 if ~iscell(d) && ~isempty(d) 109 d = cellstr(d); 110 end 111 end 112 if nargin<3 113 c = {}; 114 else 115 c = varargin{3}; 116 if ~iscell(c) && ~isempty(c) 117 c = cellstr(c); 118 end 119 end 120 % Get data, number of observations and number of variables. 121 o.data = a; 122 % Get the first date and set the frequency. 123 if isempty(b) 124 init = dates(1,1); 125 elseif (isdates(b) && isequal(length(b),1)) 126 init = b; 127 elseif ischar(b) && isdate(b)% Weekly, Monthly, Quaterly or Annual data (string). 128 init = dates(b); 129 elseif (isnumeric(b) && isscalar(b) && isint(b)) % Yearly data. 130 init = dates([num2str(b) 'Y']); 131 elseif isdates(b) % Range of dates 132 init = b(1); 133 if nobs(o)>1 && ~isequal(b.ndat(),nobs(o)) 134 error('dseries:WrongInputArguments', ['If second input is a range, its number ' ... 135 'of elements must match\nthe number of rows in the ' ... 136 'first input, unless the first input\nhas only one row.']); 137 elseif isequal(nobs(o), 1) 138 o.data = repmat(o.data,b.ndat(),1); 139 end 140 o.dates = b; 141 elseif (isnumeric(b) && isint(b)) % Range of yearly dates. 142 error('dseries:WrongInputArguments', ['Not implemented! If you need to define ' ... 143 'a range of years, you have to pass a dates object as the ' ... 144 'second input argument']); 145 else 146 error('dseries:WrongInputArguments', 'Wrong calling sequence! Please check the manual.'); 147 end 148 % Get the names of the variables. 149 if ~isempty(c) 150 if vobs(o)==length(c) 151 for i=1:vobs(o) 152 o.name = vertcat(o.name, c(i)); 153 end 154 else 155 error('dseries:WrongInputArguments', 'The number of declared names does not match the number of variables!') 156 end 157 else 158 o.name = default_name(vobs(o)); 159 end 160 o.ops = cell(length(o.name), 1); 161 o.tags = struct(); 162 if ~isempty(d) 163 if vobs(o)==length(d) 164 for i=1:vobs(o) 165 o.tex = vertcat(o.tex, d(i)); 166 end 167 else 168 error('dseries:WrongInputArguments', 'The number of declared tex names does not match the number of variables!') 169 end 170 else 171 o.tex = name2tex(o.name); 172 end 173 otherwise 174 error('dseries:WrongInputArguments', 'Wrong calling sequence! Please check the manual.') 175 end 176 if isempty(o.dates) 177 o.dates = init:init+(nobs(o)-1); 178 end 179 end % dseries 180end % methods 181end % classdef 182 183%@test:1 184%$ % Test if we can instantiate an empty dseries object. 185%$ try 186%$ ts = dseries(); 187%$ t(1) = 1; 188%$ catch 189%$ t(1) = 0; 190%$ end 191%$ 192%$ T = all(t); 193%@eof:1 194 195%@test:2 196%$ t = zeros(4,1); 197%$ 198%$ try 199%$ aa = dates('1938M11'); 200%$ ts = dseries(aa); 201%$ t(1) = 1; 202%$ catch 203%$ t = 0; 204%$ end 205%$ 206%$ if length(t)>1 207%$ t(2) = dassert(ts.freq,12); 208%$ t(3) = dassert(ts.init.freq,12); 209%$ t(4) = dassert(ts.init.time,[1938, 11]); 210%$ end 211%$ 212%$ T = all(t); 213%@eof:2 214 215%@test:3 216%$ t = zeros(8, 1); 217%$ 218%$ try 219%$ dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m',''); 220%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data.m' ]); 221%$ t(1) = 1; 222%$ catch 223%$ t = 0; 224%$ end 225%$ 226%$ if length(t)>1 227%$ t(2) = dassert(ts.freq,4); 228%$ t(3) = dassert(ts.init.freq,4); 229%$ t(4) = dassert(ts.init.time,[1994, 3]); 230%$ t(5) = dassert(ts.vobs,2); 231%$ t(6) = dassert(ts.nobs,100); 232%$ t(7) = dassert(length(ts.ops), 2); 233%$ t(8) = isempty(ts.ops{1}) && isempty(ts.ops{2}); 234%$ end 235%$ 236%$ T = all(t); 237%@eof:3 238 239%@test:4 240%$ t = zeros(8, 1); 241%$ 242%$ try 243%$ dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m',''); 244%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data.mat' ]); 245%$ t(1) = 1; 246%$ catch 247%$ t = 0; 248%$ end 249%$ 250%$ if length(t)>1 251%$ t(2) = dassert(ts.freq,4); 252%$ t(3) = dassert(ts.init.freq,4); 253%$ t(4) = dassert(ts.init.time,[1994, 3]); 254%$ t(5) = dassert(ts.vobs,2); 255%$ t(6) = dassert(ts.nobs,100); 256%$ t(7) = dassert(length(ts.ops), 2); 257%$ t(8) = isempty(ts.ops{1}) && isempty(ts.ops{2}); 258%$ end 259%$ 260%$ T = all(t); 261%@eof:4 262 263%@test:5 264%$ t = zeros(10, 1); 265%$ 266%$ try 267%$ dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m',''); 268%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data.csv' ]); 269%$ t(1) = 1; 270%$ catch 271%$ t = 0; 272%$ end 273%$ 274%$ if length(t)>1 275%$ t(2) = dassert(ts.freq,4); 276%$ t(3) = dassert(ts.init.freq,4); 277%$ t(4) = dassert(ts.init.time,[1990, 1]); 278%$ t(5) = dassert(ts.vobs,4); 279%$ t(6) = dassert(ts.nobs,4); 280%$ t(7) = dassert(ts.name,{'azert';'yuiop';'qsdfg';'jklm'}); 281%$ t(8) = dassert(ts.tex,{'azert';'yuiop';'qsdfg';'jklm'}); 282%$ t(9) = dassert(length(ts.ops), 4); 283%$ t(10) = isempty(ts.ops{1}) && isempty(ts.ops{2}) && isempty(ts.ops{3}) && isempty(ts.ops{4}) ; 284%$ end 285%$ 286%$ T = all(t); 287%@eof:5 288 289%@test:6 290%$ t = zeros(10, 1); 291%$ 292%$ try 293%$ ts = dseries(transpose(1:5),[]); 294%$ t(1) = 1; 295%$ catch 296%$ t = 0; 297%$ end 298%$ 299%$ if length(t)>1 300%$ t(2) = dassert(ts.freq,1); 301%$ t(3) = dassert(ts.init.freq,1); 302%$ t(4) = dassert(ts.init.time,[1, 1]); 303%$ t(5) = dassert(ts.vobs,1); 304%$ t(6) = dassert(ts.nobs,5); 305%$ t(7) = dassert(ts.name,{'Variable_1'}); 306%$ t(8) = dassert(ts.tex,{'Variable\\_1'}); 307%$ t(9) = dassert(length(ts.ops), 1); 308%$ t(10) = isempty(ts.ops{1}); 309%$ end 310%$ 311%$ T = all(t); 312%@eof:6 313 314%@test:7 315%$ t = zeros(10, 1); 316%$ 317%$ try 318%$ ts = dseries(transpose(1:5),'1950Q1'); 319%$ t(1) = 1; 320%$ catch 321%$ t = 0; 322%$ end 323%$ 324%$ if length(t)>1 325%$ t(2) = dassert(ts.freq,4); 326%$ t(3) = dassert(ts.init.freq,4); 327%$ t(4) = dassert(ts.init.time,[1950, 1]); 328%$ t(5) = dassert(ts.vobs,1); 329%$ t(6) = dassert(ts.nobs,5); 330%$ t(7) = dassert(ts.name,{'Variable_1'}); 331%$ t(8) = dassert(ts.tex,{'Variable\\_1'}); 332%$ t(9) = dassert(length(ts.ops), 1); 333%$ t(10) = isempty(ts.ops{1}); 334%$ end 335%$ 336%$ T = all(t); 337%@eof:7 338 339%@test:8 340%$ t = zeros(10, 1); 341%$ 342%$ try 343%$ ts = dseries([transpose(1:5), transpose(6:10)],'1950q1',{'Output'; 'Consumption'}, {'Y_t'; 'C_t'}); 344%$ t(1) = 1; 345%$ catch 346%$ t = 0; 347%$ end 348%$ 349%$ if length(t)>1 350%$ t(2) = dassert(ts.freq,4); 351%$ t(3) = dassert(ts.init.freq,4); 352%$ t(4) = dassert(ts.init.time,[1950, 1]); 353%$ t(5) = dassert(ts.vobs,2); 354%$ t(6) = dassert(ts.nobs,5); 355%$ t(7) = dassert(ts.name,{'Output'; 'Consumption'}); 356%$ t(8) = dassert(ts.tex,{'Y_t'; 'C_t'}); 357%$ t(9) = dassert(length(ts.ops), 2); 358%$ t(10) = isempty(ts.ops{1}) && isempty(ts.ops{2}); 359%$ end 360%$ 361%$ T = all(t); 362%@eof:8 363 364%@test:9 365%$ try 366%$ dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m',''); 367%$ if isoctave() 368%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-1.xlsx' ]); 369%$ else 370%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-1.xls' ]); 371%$ end 372%$ t(1) = 1; 373%$ catch 374%$ t(1) = 0; 375%$ end 376%$ 377%$ if t(1) 378%$ t(2) = dassert(ts.freq,4); 379%$ t(3) = dassert(ts.init.freq,4); 380%$ t(4) = dassert(ts.init.time,[1990, 1]); 381%$ t(5) = dassert(ts.vobs,3); 382%$ t(6) = dassert(ts.nobs,5); 383%$ t(7) = dassert(ts.name,{'GDP';'Consumption';'CPI'}); 384%$ t(8) = dassert(ts.tex,{'GDP';'Consumption';'CPI'}); 385%$ t(9) = dassert(length(ts.ops), 3); 386%$ t(10) = isempty(ts.ops{1}) && isempty(ts.ops{2}) && isempty(ts.ops{3}); 387%$ end 388%$ 389%$ T = all(t); 390%@eof:9 391 392%@test:10 393%$ try 394%$ dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m',''); 395%$ if isoctave() 396%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-2.xlsx' ]); 397%$ else 398%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-2.xls' ]); 399%$ end 400%$ t(1) = 1; 401%$ catch 402%$ t(1) = 0; 403%$ end 404%$ 405%$ if t(1) 406%$ t(2) = dassert(ts.freq,4); 407%$ t(3) = dassert(ts.init.freq,4); 408%$ t(4) = dassert(ts.init.time,[1990, 1]); 409%$ t(5) = dassert(ts.vobs,3); 410%$ t(6) = dassert(ts.nobs,5); 411%$ t(7) = dassert(ts.name,{'Variable_1';'Variable_2';'Variable_3'}); 412%$ t(8) = dassert(ts.tex,{'Variable\\_1';'Variable\\_2';'Variable\\_3'}); 413%$ t(9) = dassert(length(ts.ops), 3); 414%$ t(10) = isempty(ts.ops{1}) && isempty(ts.ops{2}) && isempty(ts.ops{3}); 415%$ end 416%$ 417%$ T = all(t); 418%@eof:10 419 420%@test:11 421%$ try 422%$ dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m',''); 423%$ if isoctave() 424%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-3.xlsx' ]); 425%$ else 426%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-3.xls' ]); 427%$ end 428%$ t(1) = 1; 429%$ catch 430%$ t(1) = 0; 431%$ end 432%$ 433%$ if t(1) 434%$ t(2) = dassert(ts.freq,1); 435%$ t(3) = dassert(ts.init.freq,1); 436%$ t(4) = dassert(ts.init.time,[1, 1]); 437%$ t(5) = dassert(ts.vobs,3); 438%$ t(6) = dassert(ts.nobs,5); 439%$ t(7) = dassert(ts.name,{'Variable_1';'Variable_2';'Variable_3'}); 440%$ t(8) = dassert(ts.tex,{'Variable\\_1';'Variable\\_2';'Variable\\_3'}); 441%$ t(9) = dassert(length(ts.ops), 3); 442%$ t(10) = isempty(ts.ops{1}) && isempty(ts.ops{2}) && isempty(ts.ops{3}); 443%$ end 444%$ 445%$ T = all(t); 446%@eof:11 447 448%@test:12 449%$ try 450%$ dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m',''); 451%$ if isoctave() 452%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-4.xlsx' ]); 453%$ else 454%$ ts = dseries([ dseries_src_root '../tests/data/dynseries_test_data-4.xls' ]); 455%$ end 456%$ t(1) = 1; 457%$ catch 458%$ t(1) = 0; 459%$ end 460%$ 461%$ if t(1) 462%$ t(2) = dassert(ts.freq,1); 463%$ t(3) = dassert(ts.init.freq,1); 464%$ t(4) = dassert(ts.init.time,[1, 1]); 465%$ t(5) = dassert(ts.vobs,3); 466%$ t(6) = dassert(ts.nobs,5); 467%$ t(7) = dassert(ts.name,{'GDP';'Consumption';'CPI'}); 468%$ t(8) = dassert(ts.tex,{'GDP';'Consumption';'CPI'}); 469%$ t(9) = dassert(length(ts.ops), 3); 470%$ t(10) = isempty(ts.ops{1}) && isempty(ts.ops{2}) && isempty(ts.ops{3}); 471%$ end 472%$ 473%$ T = all(t); 474%@eof:12 475 476%@test:13 477%$ t = zeros(8, 1); 478%$ 479%$ try 480%$ ts = dseries(transpose(1:4),dates('1990Q1'):dates('1990Q4')); 481%$ t(1) = 1; 482%$ catch 483%$ t = 0; 484%$ end 485%$ 486%$ if length(t)>1 487%$ t(2) = dassert(ts.freq,4); 488%$ t(3) = dassert(ts.init.freq,4); 489%$ t(4) = dassert(ts.init.time,[1990, 1]); 490%$ t(5) = dassert(ts.vobs,1); 491%$ t(6) = dassert(ts.nobs,4); 492%$ t(7) = dassert(length(ts.ops), 1); 493%$ t(8) = isempty(ts.ops{1}); 494%$ end 495%$ 496%$ T = all(t); 497%@eof:13 498 499%@test:14 500%$ t = zeros(9, 1); 501%$ 502%$ try 503%$ ts = dseries([1, 2],dates('1990Q1'):dates('1990Q4')); 504%$ t(1) = 1; 505%$ catch 506%$ t = 0; 507%$ end 508%$ 509%$ if length(t)>1 510%$ t(2) = dassert(ts.freq,4); 511%$ t(3) = dassert(ts.init.freq,4); 512%$ t(4) = dassert(ts.init.time,[1990, 1]); 513%$ t(5) = dassert(ts.vobs,2); 514%$ t(6) = dassert(ts.nobs,4); 515%$ t(7) = dassert(ts.data, [ones(4,1), 2*ones(4,1)]); 516%$ t(8) = dassert(length(ts.ops), 2); 517%$ t(9) = isempty(ts.ops{1}) && isempty(ts.ops{2}); 518%$ end 519%$ 520%$ T = all(t); 521%@eof:14 522 523%@test:15 524%$ try 525%$ evalc('dseries([1; 2],dates(''1990Q1''):dates(''1990Q4''));'); 526%$ t = 0; 527%$ catch 528%$ t = 1; 529%$ end 530%$ 531%$ T = all(t); 532%@eof:15 533