1function r = subsref(o, S) % --*-- Unitary tests --*--
2
3% Overloads the subsref method for dseries class.
4%
5% INPUTS
6% - o    [dseries]    Time series object instantiated by dseries.
7% - S    [struct]     Matlab's structure array S with two fields, type and subs. The type field is
8%                     a string containing '()', '{}', or '.', where '()' specifies integer
9%                     subscripts, '{}' specifies cell array subscripts, and '.' specifies
10%                     subscripted structure fields. The subs field is a cell array or a string
11%                     containing the actual subscripts (see matlab's documentation).
12%
13% OUTPUTS
14% - r    [dseries]    Depending on the calling sequence `r` is a transformation of `o` obtained
15%                     by applying a public method on `o`, or a dseries object built by extracting
16%                     a variable from `o`, or a dseries object containing a subsample.
17
18% Copyright (C) 2011-2019 Dynare Team
19%
20% This file is part of Dynare.
21%
22% Dynare is free software: you can redistribute it and/or modify
23% it under the terms of the GNU General Public License as published by
24% the Free Software Foundation, either version 3 of the License, or
25% (at your option) any later version.
26%
27% Dynare is distributed in the hope that it will be useful,
28% but WITHOUT ANY WARRANTY; without even the implied warranty of
29% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30% GNU General Public License for more details.
31%
32% You should have received a copy of the GNU General Public License
33% along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
34
35switch S(1).type
36  case '.'
37    switch S(1).subs
38      case {'data','name','tex','dates','ops', 'tags'}        % Public members.
39        if length(S)>1 && isequal(S(2).type,'()') && isempty(S(2).subs)
40            error(['dseries::subsref: ' S(1).subs ' is not a method but a member!'])
41        end
42        r = builtin('subsref', o, S(1));
43      case 'nobs'
44        % Returns the number of observations.
45        r = rows(o.data);
46      case 'vobs'
47        % Returns the number of variables.
48        r = columns(o.data);
49      case 'init'
50        % Returns a dates object (first date).
51        r = o.dates(1);
52      case 'last'
53        % Returns a dates object (last date).
54        r = o.dates(end);
55      case 'freq'
56        % Returns an integer characterizing the data frequency (1, 4, 12 or 52)
57        r = o.dates.freq;
58      case 'length'
59        error(['dseries::subsref: we do not support the length operator on ' ...
60               'dseries. Please use ''nobs'' or ''vobs''']);
61      case 'save'
62        % Save dseries object on disk (default is a mat file).
63        r = NaN;
64        if isequal(length(S),2)
65            if strcmp(S(2).type,'()')
66                if isempty(S(2).subs)
67                    save(o);
68                else
69                    if isempty(S(2).subs{1})
70                        save(o,'',S(2).subs{2});
71                    else
72                        save(o,S(2).subs{:});
73                    end
74                end
75                S = shiftS(S,1);
76            else
77                error('dseries::subsref: Wrong syntax.')
78            end
79        elseif isequal(length(S),1)
80            save(o);
81        else
82            error('dseries::subsref: Call to save method must come in last position!')
83        end
84      case 'struct'
85        r = dseries2struct(o);
86      case 'initialize'
87        r = NaN;
88        initialize(o);
89      case {'baxter_king_filter', 'baxter_king_filter_', ...
90            'cumsum','cumsum_', ...
91            'insert', ...
92            'pop','pop_', ...
93            'cumprod','cumprod_', ...
94            'remove','remove_', ...
95            'onesidedhptrend','onesidedhptrend_', ...
96            'onesidedhpcycle','onesidedhpcycle_', ...
97            'lag','lag_', ...
98            'lead','lead_', ...
99            'hptrend','hptrend_', ...
100            'hpcycle','hpcycle_', ...
101            'chain','chain_', ...
102            'backcast','backcast_', ...
103            'detrend','detrend_', ...
104            'exist', ...
105            'mean', ...
106            'nanmean', ...
107            'std', ...
108            'center','center_', ...
109            'log','log_', ...
110            'exp','exp_', ...
111            'ygrowth','ygrowth_', ...
112            'qgrowth','qgrowth_', ...
113            'mgrowth','mgrowth_', ...
114            'ydiff','ydiff_', ...
115            'qdiff','qdiff_', ...
116            'diff', 'diff_', ...
117            'mdiff','mdiff_', ...
118            'abs','abs_', ...
119            'isnan', ...
120            'isinf', ...
121            'isreal', ...
122            'firstdate', ...
123            'lastdate', ...
124            'firstobservedperiod', ...
125            'lastobservedperiod', ...
126            'lineartrend', ...
127            'resetops', 'resettags', ...
128            'subsample'}
129        if length(S)>1 && isequal(S(2).type,'()')
130            if isempty(S(2).subs)
131                r = feval(S(1).subs,o);
132                S = shiftS(S,1);
133            else
134                r = feval(S(1).subs,o,S(2).subs{:});
135                S = shiftS(S,1);
136            end
137        else
138            r = feval(S(1).subs,o);
139        end
140      case 'size'
141        if isequal(length(S),2) && strcmp(S(2).type,'()')
142            if isempty(S(2).subs)
143                [x,y] = size(o);
144                r = [x, y];
145            else
146                r = size(o,S(2).subs{1});
147            end
148            S = shiftS(S,1);
149        elseif isequal(length(S),1)
150            [x,y] = size(o);
151            r = [x, y];
152        else
153            error('dseries::subsref: Call to size method must come in last position!')
154        end
155      case {'set_names','rename','rename_','tex_rename','tex_rename_', 'tag'}
156        r = feval(S(1).subs,o,S(2).subs{:});
157        S = shiftS(S,1);
158      case {'disp'}
159        feval(S(1).subs,o);
160        return
161      otherwise                                                            % Extract a sub-object by selecting one variable.
162        ndx = find(strcmp(S(1).subs,o.name));
163        if ~isempty(ndx)
164            r = dseries();
165            r.data = o.data(:,ndx);
166            r.name = o.name(ndx);
167            r.tex = o.tex(ndx);
168            r.dates = o.dates;
169            r.ops = o.ops(ndx);
170            tagnames = fieldnames(o.tags);
171            for i=1:length(tagnames)
172                r.tags.(tagnames{i}) = o.tags.(tagnames{i})(ndx);
173            end
174        else
175            error('dseries::subsref: Unknown public method, public member or variable!')
176        end
177    end
178  case '()'
179    if ischar(S(1).subs{1}) && ~isdate(S(1).subs{1})
180        % If ts is an empty dseries object, populate this object by reading data in a file.
181        if isempty(o)
182            if exist(S(1).subs{1}, 'file')
183                r = dseries(S(1).subs{1});
184            else
185                error('dseries::subsref: Cannot find file %s', S(1).subs{1})
186            end
187        else
188            error('dseries::subsref: dseries object is not empty!')
189        end
190    elseif isscalar(S(1).subs{1}) && isint(S(1).subs{1})
191        % Input is also interpreted as a backward/forward operator
192        if S(1).subs{1}>0
193            r = lead(o, S(1).subs{1});
194        elseif S(1).subs{1}<0
195            r = lag(o, -S(1).subs{1});
196        else
197            % Do nothing.
198            r = o;
199        end
200    elseif isdates(S(1).subs{1}) || isdate(S(1).subs{1})
201        % Select observation(s) with date(s)
202        if isdate(S(1).subs{1})
203            Dates = dates(S(1).subs{1});
204        else
205            Dates = S(1).subs{1};
206        end
207        % Test if Dates is out of bounds
208        if min(Dates)<min(o.dates)
209            error(['dseries::subsref: Indices are out of bounds! Subsample cannot start before ' date2string(o.dates(1)) '.'])
210        end
211        if  max(Dates)>max(o.dates)
212            error(['dseries::subsref: Indices are out of bounds! Subsample cannot end after ' date2string(o.dates(end)) '.'])
213        end
214        % Extract a subsample using a dates object
215        [~,tdx] = intersect(o.dates.time,Dates.time,'rows');
216        r = copy(o);
217        r.data = r.data(tdx,:);
218        r.dates = r.dates(tdx);
219    elseif isnumeric(S(1).subs{1}) && isequal(ndims(S(1).subs{1}), 2)
220        if isempty(o)
221            % Populate an empty dseries object.
222            if isempty(o.dates)
223                r = copy(o);
224                r.dates = dates('1Y'):dates('1Y')+(rows(S(1).subs{1})-1);
225                r.data = S(1).subs{1};
226                r.name = default_name(columns(r.data));
227                r.tex = name2tex(r.name);
228                r.ops = cell(length(r.name), 1);
229            else
230                r = copy(o);
231                r.dates = r.dates:r.dates+(rows(S(1).subs{1})-1);
232                r.data = S(1).subs{1};
233                r.name = default_name(columns(r.data));
234                r.tex = name2tex(r.name);
235                r.ops = cell(length(r.name), 1);
236            end
237        else
238            error('dseries::subsref: It is not possible to populate a non empty dseries object!');
239        end
240    else
241        error('dseries::subsref: I have no idea of what you are trying to do!')
242    end
243  case '{}'
244    if iscellofchar(S(1).subs)
245        r = extract(o,S(1).subs{:});
246    elseif isequal(length(S(1).subs),1) && all(isint(S(1).subs{1}))
247        idx = S(1).subs{1};
248        if max(idx)>size(o.data,2) || min(idx)<1
249            error('dseries::subsref: Indices are out of bounds!')
250        end
251        r = dseries();
252        r.data = o.data(:,idx);
253        r.name = o.name(idx);
254        r.tex  = o.tex(idx);
255        r.dates = o.dates;
256        r.ops = o.ops(idx);
257        tagnames = fieldnames(o.tags);
258        for i=1:length(tagnames)
259            r.tags.(tagnames{i}) = o.tags.(tagnames{i})(idx);
260        end
261    else
262        error('dseries::subsref: What the Hell are you tryin'' to do?!')
263    end
264  otherwise
265    error('dseries::subsref: What the Hell are you doin'' here?!')
266end
267
268S = shiftS(S,1);
269if ~isempty(S)
270    r = subsref(r, S);
271end
272
273return
274
275%@test:1
276 % Define a data set.
277 A = [transpose(1:10),2*transpose(1:10)];
278
279 % Define names
280 A_name = {'A1';'A2'};
281
282 % Instantiate a time series object.
283 ts1 = dseries(A,[],A_name,[]);
284
285 % Call the tested method.
286 a = ts1(ts1.dates(2:9));
287
288 % Expected results.
289 e.data = [transpose(2:9),2*transpose(2:9)];
290 e.nobs = 8;
291 e.vobs = 2;
292 e.name = {'A1';'A2'};
293 e.freq = 1;
294 e.init = dates(1,2);
295
296 % Check the results.
297 t(1) = dassert(a.data,e.data);
298 t(2) = dassert(a.nobs,e.nobs);
299 t(3) = dassert(a.vobs,e.vobs);
300 t(4) = dassert(a.freq,e.freq);
301 t(5) = dassert(a.init,e.init);
302 T = all(t);
303%@eof:1
304
305%@test:2
306 % Define a data set.
307 A = [transpose(1:10),2*transpose(1:10)];
308
309 % Define names
310 A_name = {'A1';'A2'};
311
312 % Instantiate a time series object.
313 ts1 = dseries(A,[],A_name,[]);
314
315 % Call the tested method.
316 a = ts1.A1;
317
318 % Expected results.
319 e.data = transpose(1:10);
320 e.nobs = 10;
321 e.vobs = 1;
322 e.name = {'A1'};
323 e.freq = 1;
324 e.init = dates(1,1);
325
326 % Check the results.
327 t(1) = dassert(a.data,e.data);
328 t(2) = dassert(a.init,e.init);
329 t(3) = dassert(a.nobs,e.nobs);
330 t(4) = dassert(a.vobs,e.vobs);
331 t(5) = dassert(a.freq,e.freq);
332 T = all(t);
333%@eof:2
334
335%@test:3
336 % Define a data set.
337 A = [transpose(1:10),2*transpose(1:10)];
338
339 % Define names
340 A_name = {'A1';'A2'};
341
342 % Instantiate a time series object.
343 ts1 = dseries(A,[],A_name,[]);
344
345 % Call the tested method.
346 a = ts1.log;
347
348 % Expected results.
349 e.data = log(A);
350 e.nobs = 10;
351 e.vobs = 2;
352 e.name = {'A1';'A2'};
353 e.freq = 1;
354 e.init = dates(1,1);
355
356 % Check the results.
357 t(1) = dassert(a.data,e.data);
358 t(2) = dassert(a.nobs,e.nobs);
359 t(3) = dassert(a.vobs,e.vobs);
360 t(4) = dassert(a.freq,e.freq);
361 t(5) = dassert(a.init,e.init);
362 T = all(t);
363%@eof:3
364
365%@test:4
366 % Create an empty dseries object.
367 dataset = dseries();
368
369 t = zeros(5,1);
370
371 try
372    dseries_src_root = strrep(which('initialize_dseries_class'),'initialize_dseries_class.m','');
373    A = dseries([ dseries_src_root '../tests/data/dynseries_test_data.csv' ]);
374    t(1) = 1;
375 catch
376    t = 0;
377 end
378
379 % Check the results.
380 if length(t)>1
381     t(2) = dassert(A.nobs,4);
382     t(3) = dassert(A.vobs,4);
383     t(4) = dassert(A.freq,4);
384     t(5) = dassert(A.init,dates('1990Q1'));
385 end
386 T = all(t);
387%@eof:4
388
389%@test:5
390 % Define a data set.
391 A = [transpose(1:10),2*transpose(1:10),3*transpose(1:10)];
392
393 % Define names
394 A_name = {'A1';'A2';'B1'};
395
396 % Instantiate a time series object.
397 ts1 = dseries(A,[],A_name,[]);
398
399 % Call the tested method.
400 a = ts1{'A1','B1'};
401
402 % Expected results.
403 e.data = A(:,[1,3]);
404 e.nobs = 10;
405 e.vobs = 2;
406 e.name = {'A1';'B1'};
407 e.freq = 1;
408 e.init = dates(1,1);
409
410 t(1) = dassert(e.data,a.data);
411 t(2) = dassert(e.nobs,a.nobs);
412 t(3) = dassert(e.vobs,a.vobs);
413 t(4) = dassert(e.name,a.name);
414 t(5) = dassert(e.init,a.init);
415 T = all(t);
416%@eof:5
417
418%@test:6
419 % Define a data set.
420 A = rand(10,24);
421
422 % Define names
423 A_name = {'GDP_1';'GDP_2';'GDP_3'; 'GDP_4'; 'GDP_5'; 'GDP_6'; 'GDP_7'; 'GDP_8'; 'GDP_9'; 'GDP_10'; 'GDP_11'; 'GDP_12'; 'HICP_1';'HICP_2';'HICP_3'; 'HICP_4'; 'HICP_5'; 'HICP_6'; 'HICP_7'; 'HICP_8'; 'HICP_9'; 'HICP_10'; 'HICP_11'; 'HICP_12';};
424
425 % Instantiate a time series object.
426 ts1 = dseries(A,[],A_name,[]);
427
428 % Call the tested method.
429 try
430     a = ts1{'[GDP_[0-9]]'};
431     t(1) = 1;
432 catch
433     t(1) = 0;
434 end
435 try
436     b = ts1{'[[A-Z]*_1]'};
437     t(2) = 1;
438 catch
439     t(2) = 0;
440 end
441 try
442     warning off all
443     c = ts1{'[A-Z]_1'};
444     warning on all
445     t(3) = 0;
446 catch
447     t(3) = 1;
448 end
449
450 % Expected results.
451 e1.data = A(:,1:9);
452 e1.nobs = 10;
453 e1.vobs = 9;
454 e1.name = {'GDP_1';'GDP_2';'GDP_3'; 'GDP_4'; 'GDP_5'; 'GDP_6'; 'GDP_7'; 'GDP_8'; 'GDP_9'};
455 e1.freq = 1;
456 e1.init = dates(1,1);
457 e2.data = A(:,[1 13]);
458 e2.nobs = 10;
459 e2.vobs = 2;
460 e2.name = {'GDP_1';'HICP_1'};
461 e2.freq = 1;
462 e2.init = dates(1,1);
463
464 % Check results.
465 t(4) = dassert(e1.data,a.data);
466 t(5) = dassert(e1.nobs,a.nobs);
467 t(6) = dassert(e1.vobs,a.vobs);
468 t(7) = dassert(e1.name,a.name);
469 t(8) = dassert(e1.init,a.init);
470 t(9) = dassert(e2.data,b.data);
471 t(10) = dassert(e2.nobs,b.nobs);
472 t(11) = dassert(e2.vobs,b.vobs);
473 t(12) = dassert(e2.name,b.name);
474 t(13) = dassert(e2.init,b.init);
475 T = all(t);
476%@eof:6
477
478%@test:7
479 % Define a data set.
480 A = [transpose(1:10),2*transpose(1:10)];
481
482 % Define names
483 A_name = {'A1';'A2'};
484
485 % Instantiate a time series object.
486 try
487    ts1 = dseries(A,[],A_name,[]);
488    ts1.save('ts1');
489    t = 1;
490 catch
491    t = 0;
492 end
493
494 delete('ts1.mat');
495
496 T = all(t);
497%@eof:7
498
499%@test:8
500 % Define a data set.
501 A = [transpose(1:10),2*transpose(1:10)];
502
503 % Define names
504 A_name = {'A1';'A2'};
505
506 % Instantiate a time series object.
507 try
508    ts1 = dseries(A,[],A_name,[]);
509    ts1.save('test_generated_data_file','m');
510    delete('test_generated_data_file.m');
511    t = 1;
512 catch
513    t = 0;
514 end
515
516 T = all(t);
517%@eof:8
518
519%@test:9
520 % Define a data set.
521 A = [transpose(1:60),2*transpose(1:60),3*transpose(1:60)];
522
523 % Define names
524 A_name = {'A1';'A2';'B1'};
525
526 % Instantiate a time series object.
527 ts1 = dseries(A,'1971Q1',A_name,[]);
528
529 % Define the range of a subsample.
530 range = dates('1971Q2'):dates('1971Q4');
531 % Call the tested method.
532 a = ts1(range);
533
534 % Expected results.
535 e.data = A(2:4,:);
536 e.nobs = 3;
537 e.vobs = 3;
538 e.name = {'A1';'A2';'B1'};
539 e.freq = 4;
540 e.init = dates('1971Q2');
541
542 t(1) = dassert(e.data,a.data);
543 t(2) = dassert(e.nobs,a.nobs);
544 t(3) = dassert(e.vobs,a.vobs);
545 t(4) = dassert(e.name,a.name);
546 t(5) = dassert(e.init,a.init);
547 T = all(t);
548%@eof:9
549
550%@test:10
551 % Define a data set.
552 A = [transpose(1:60),2*transpose(1:60),3*transpose(1:60)];
553
554 % Define names
555 A_name = {'A1';'A2';'B1'};
556
557 % Instantiate a time series object.
558 ts1 = dseries(A,'1971Q1',A_name,[]);
559
560 % Test the size method.
561 B = ts1.size();
562 C = ts1.size(1);
563 D = ts1.size(2);
564 E = ts1.size;
565
566 t(1) = dassert(B,[60, 3]);
567 t(2) = dassert(E,[60, 3]);
568 t(3) = dassert(C,60);
569 t(4) = dassert(D,3);
570 T = all(t);
571%@eof:10
572
573%@test:11
574 % Define a data set.
575 A = [transpose(1:60),2*transpose(1:60),3*transpose(1:60)];
576
577 % Define names
578 A_name = {'A1';'A2';'B1'};
579
580 % Instantiate a time series object.
581 ts1 = dseries(A,'1971Q1',A_name,[]);
582
583 % Test the size method.
584 B = ts1{1};
585 C = ts1{[1,3]};
586 D = ts1{'A1'};
587
588 t(1) = dassert(B.name{1},'A1');
589 t(2) = dassert(B.data,A(:,1));
590 t(3) = dassert(C.name{1},'A1');
591 t(4) = dassert(C.data(:,1),A(:,1));
592 t(5) = dassert(C.name{2},'B1');
593 t(6) = dassert(C.data(:,2),A(:,3));
594 t(7) = dassert(D.name{1},'A1');
595 t(8) = dassert(D.data,A(:,1));
596 T = all(t);
597%@eof:11
598
599%@test:12
600 % Define a data set.
601 A = [transpose(1:10),2*transpose(1:10)];
602
603 % Define names
604 A_name = {'A1';'A2'};
605
606 % Instantiate a time series object.
607 try
608    ts1 = dseries(A,[],A_name,[]);
609    ts1.save();
610    t = 1;
611 catch
612    t = 0;
613 end
614
615 delete('dynare_series.mat')
616
617 T = all(t);
618%@eof:12
619
620%@test:13
621 try
622     data = transpose(0:1:50);
623     ts = dseries(data,'1950Q1');
624     a = ts.lag;
625     b = ts.lead;
626     c = ts(-1);
627     d = ts(1);
628     t(1) = 1;
629 catch
630     t(1) = 0;
631 end
632
633 if t(1)>1
634     t(2) = (a==c);
635     t(3) = (b==d);
636 end
637
638 T = all(t);
639%@eof:13
640
641%@test:14
642 try
643     ds = dseries(transpose(1:5));
644     ts = ds(ds.dates(2:3));
645     t(1) = 1;
646 catch
647     t(1) = 0;
648 end
649
650 if t(1)>1
651     t(2) = isdseries(ts);
652     t(3) = isequal(ts.data,ds.data(2:3));
653 end
654
655 T = all(t);
656%@eof:14
657
658%@test:15
659 try
660     ds = dseries(transpose(1:5));
661     ts = ds(ds.dates(2:6));
662     t(1) = 0;
663 catch
664     t(1) = 1;
665 end
666
667 T = all(t);
668%@eof:15
669
670%@test:16
671 try
672     ds = dseries(transpose(1:5));
673     ts = ds(dates('1Y'):dates('6Y'));
674     t(1) = 0;
675 catch
676     t(1) = 1;
677 end
678
679 T = all(t);
680%@eof:16
681
682%@test:17
683 try
684     ds = dseries(transpose(1:5));
685     ts = ds(dates('-2Y'):dates('4Y'));
686     t(1) = 0;
687 catch
688     t(1) = 1;
689 end
690
691 T = all(t);
692%@eof:17
693
694%@test:18
695 try
696     tseries = dseries();
697     ts = tseries(ones(10,1));
698     t(1) = true;
699 catch
700     t(1) = false;
701 end
702
703 if t(1)
704     t(2) = ts.dates(1)==dates('1Y');
705     t(3) = ts.dates(10)==dates('10Y');
706 end
707
708 T = all(t);
709%@eof:18
710
711%@test:19
712 try
713     tseries = dseries(dates('2000Q1'));
714     ts = tseries(ones(5,1));
715     t(1) = true;
716 catch
717     t(1) = false;
718 end
719
720 if t(1)
721     t(2) = ts.dates(1)==dates('2000Q1');
722     t(3) = ts.dates(5)==dates('2001Q1');
723 end
724
725 T = all(t);
726%@eof:19
727