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