merge.m 7.31 KB
Newer Older
1
function q = merge(o, p, legacy) % --*-- Unitary tests --*--
2

3 4
% Merge method for dseries objects.
%
Stéphane Adjemian's avatar
Stéphane Adjemian committed
5
% INPUTS
6 7
% - o                [dseries]
% - p                [dseries]
8
% - legacy           [logical]      revert to legacy behaviour if `true` (default is `false`), 
9
%
Stéphane Adjemian's avatar
Stéphane Adjemian committed
10
% OUTPUTS
11
% - q                [dseries]
12
%
Stéphane Adjemian's avatar
Stéphane Adjemian committed
13
% REMARKS
14
% If dseries objects o and p have common variables, the variables
15 16
% in p take precedence except if p has NaNs (the exception can be
% removed by setting the third argument, legacy, equal to true).
17

18
% Copyright © 2013-2020 Dynare Team
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare.  If not, see <http://www.gnu.org/licenses/>.

35
if ~isdseries(p) || ~isdseries(o)
36 37 38
    error('dseries::merge: Both inputs must be dseries objects!')
end

39 40 41 42 43 44 45 46 47 48 49
if isempty(o) && ~isempty(p)
    q = p;
    return
elseif ~isempty(o) && isempty(p)
    q = o;
    return
elseif isempty(o) && isempty(p)
    q = p;
    return
end

50 51 52 53
if nargin<3
    legacy = false;
end

54
if ~isequal(frequency(o), frequency(p))
Stéphane Adjemian's avatar
Stéphane Adjemian committed
55
    if isempty(inputname(1))
56
        error('dseries::merge: Cannot merge dseries objects (frequencies are different)!')
Stéphane Adjemian's avatar
Stéphane Adjemian committed
57 58 59
    else
        error(['dseries::merge: Cannot merge ' inputname(1) ' and ' inputname(2) ' (frequencies are different)!'])
    end
60 61
end

62
q = dseries();
63

64
[q.name, IBC, ~] = unique([o.name; p.name], 'last');
65

66 67 68
if ~legacy
    [list_of_common_variables, iO, iP] = intersect(o.name, p.name);
end
69

70 71
tex = [o.tex; p.tex];
q.tex = tex(IBC);
72

Stéphane Adjemian's avatar
Stéphane Adjemian committed
73 74
ops = [o.ops; p.ops];
q.ops = ops(IBC);
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
otagnames = fieldnames(o.tags);
ptagnames = fieldnames(p.tags);
qtagnames = union(otagnames, ptagnames);
if isempty(qtagnames)
    q.tags = struct();
else
    for i=1:length(qtagnames)
        if ismember(qtagnames{i}, otagnames) && ismember(qtagnames{i}, ptagnames)
            q.tags.(qtagnames{i}) = vertcat(o.tags.(otagnames{i}), p.tags.(ptagnames{i}));
        elseif ismember(qtagnames{i}, otagnames)
            q.tags.(qtagnames{i}) = vertcat(o.tags.(qtagnames{i}), cell(vobs(p), 1));
        elseif ismember(qtagnames{i}, ptagnames)
            q.tags.(qtagnames{i}) = vertcat(cell(vobs(o), 1), p.tags.(qtagnames{i}));
        else
            error('dseries::horzcat: This is a bug!')
        end
        q.tags.(qtagnames{i}) = q.tags.(qtagnames{i})(IBC);
    end
end

96 97 98 99 100 101 102 103
if nobs(o) == 0
    q = copy(p);
elseif nobs(p) == 0
    q = copy(o);
elseif firstdate(o) >= firstdate(p)
    diff = firstdate(o) - firstdate(p);
    q_nobs = max(nobs(o) + diff, nobs(p));
    q.data = NaN(q_nobs, vobs(q));
104
    Z1 = [NaN(diff, vobs(o)); o.data];
105 106
    if nobs(q) > nobs(o) + diff
        Z1 = [Z1; NaN(nobs(q)-(nobs(o) + diff), vobs(o))];
Stéphane Adjemian's avatar
Stéphane Adjemian committed
107
    end
108 109 110
    Z2 = p.data;
    if nobs(q) > nobs(p)
        Z2 = [Z2; NaN(nobs(q) - nobs(p), vobs(p))];
Stéphane Adjemian's avatar
Stéphane Adjemian committed
111
    end
112
    Z = [Z1 Z2];
113
    q.data = Z(:,IBC);
114 115 116 117 118 119 120 121 122
    if ~legacy
        if ~isempty(list_of_common_variables)
            for i=1:length(iP)
                jO = iO(i);
                jP = iP(i);
                jQ = find(strcmp(o.name{jO}, q.name));
                id = isnan(q.data(:,jQ)) & ~isnan(Z1(:,jO)) & isnan(Z2(:,jP));
                q.data(id, jQ) = Z1(id,jO);
            end
123 124
        end
    end
125
    q_init = firstdate(p);
126
else
127 128 129 130 131 132
    diff = firstdate(p) - firstdate(o);
    q_nobs = max(nobs(p) + diff, nobs(o));
    q.data = NaN(q_nobs, vobs(q));
    Z1 = [NaN(diff, vobs(p)); p.data];
    if nobs(q) > nobs(p) + diff
        Z1 = [Z1; NaN(nobs(q)-(nobs(p) + diff), vobs(p))];
133
    end
134 135 136
    Z2 = o.data;
    if nobs(q) > nobs(o)
        Z2 = [Z2; NaN(nobs(q) - nobs(o), vobs(o))];
Stéphane Adjemian's avatar
Stéphane Adjemian committed
137
    end
138
    Z = [Z2 Z1];
139
    q.data = Z(:,IBC);
140 141 142 143 144 145 146 147 148
    if ~legacy
        if ~isempty(list_of_common_variables)
            for i=1:length(iP)
                jO = iO(i);
                jP = iP(i);
                jQ = find(strcmp(o.name{jO}, q.name));
                id = isnan(q.data(:,jQ)) & isnan(Z1(:,jP)) & ~isnan(Z2(:,jO));
                q.data(id, jQ) = Z2(id,jO);
            end
149 150
        end
    end
151
    q_init = firstdate(o);
152 153
end

154
q.dates = q_init:q_init+(nobs(q)-1);
155 156 157 158 159 160 161 162

%@test:1
%$ % Define a datasets.
%$ A = rand(10,2); B = randn(10,1);
%$
%$ % Define names
%$ A_name = {'A1';'A2'}; B_name = {'A1'};
%$
163
%$ % Instantiate two time series objects and merge.
164 165
%$ try
%$    ts1 = dseries(A,[],A_name,[]);
166 167 168
%$    ts1.tag('type');
%$    ts1.tag('type', 'A1', 'Stock');
%$    ts1.tag('type', 'A2', 'Flow');
169
%$    ts2 = dseries(B,[],B_name,[]);
170 171
%$    ts2.tag('type');
%$    ts2.tag('type', 'A1', 'Flow');
172
%$    ts3 = merge(ts1,ts2);
173
%$    t(1) = true;
174
%$ catch
175
%$    t = false;
176 177
%$ end
%$
178
%$ if t(1)
179 180 181
%$    t(2) = dassert(ts3.vobs,2);
%$    t(3) = dassert(ts3.nobs,10);
%$    t(4) = dassert(ts3.data,[B, A(:,2)],1e-15);
182
%$    t(5) = dassert(ts3.tags.type, {'Flow';'Flow'});
183 184 185 186 187 188 189 190 191 192 193
%$ end
%$ T = all(t);
%@eof:1

%@test:2
%$ % Define a datasets.
%$ A = rand(10,2); B = randn(10,1);
%$
%$ % Define names
%$ A_name = {'A1';'A2'}; B_name = {'B1'};
%$
194
%$ % Instantiate two time series objects and merge them.
195 196
%$ try
%$    ts1 = dseries(A,[],A_name,[]);
197 198 199
%$    ts1.tag('t1');
%$    ts1.tag('t1', 'A1', 'Stock');
%$    ts1.tag('t1', 'A2', 'Flow');
200
%$    ts2 = dseries(B,[],B_name,[]);
201 202
%$    ts2.tag('t2');
%$    ts2.tag('t2', 'B1', 1);
203
%$    ts3 = merge(ts1,ts2);
204
%$    t(1) = true;
205
%$ catch
206
%$    t = false;
207 208 209 210 211 212
%$ end
%$
%$ if length(t)>1
%$    t(2) = dassert(ts3.vobs,3);
%$    t(3) = dassert(ts3.nobs,10);
%$    t(4) = dassert(ts3.data,[A, B],1e-15);
213 214
%$    t(5) = dassert(ts3.tags.t1, {'Flow';'Flow';[]});
%$    t(6) = dassert(ts3.tags.t2, {[];[];1});
215 216
%$ end
%$ T = all(t);
Houtan Bastani's avatar
Houtan Bastani committed
217
%@eof:2
218 219 220 221

%@test:3
%$ % Define two dseries objects.
%$ y = dseries(ones(4,1),'1989Q1', 'u');
Stéphane Adjemian's avatar
Stéphane Adjemian committed
222
%$ z = dseries(2*ones(4,1),'1990Q1', 'u');
223 224 225 226 227 228 229 230 231 232 233 234
%$
%$ % Merge the two objects.
%$ try
%$    x = merge(y, z);
%$    t(1) = true;
%$ catch
%$    t = false;
%$ end
%$
%$ if t(1)
%$    t(2) = dassert(x.vobs,1);
%$    t(3) = dassert(x.name{1},'u');
Stéphane Adjemian's avatar
Stéphane Adjemian committed
235
%$    t(4) = all(x.data(5:end)==2) && all(x.data(1:4)==1);
236 237 238 239 240 241 242 243
%$    t(5) = all(x.dates==dates('1989Q1'):dates('1990Q4'));
%$ end
%$ T = all(t);
%@eof:3

%@test:4
%$ % Define two dseries objects.
%$ y = dseries(ones(4,1),'1989Q1', 'u');
Stéphane Adjemian's avatar
Stéphane Adjemian committed
244
%$ z = dseries([NaN(4,1); 2*ones(4,1)],'1989Q1', 'u');
245 246 247
%$
%$ % Merge the two objects.
%$ try
Stéphane Adjemian's avatar
Stéphane Adjemian committed
248
%$    x = merge(y, z);
249 250 251 252 253 254 255 256
%$    t(1) = true;
%$ catch
%$    t = false;
%$ end
%$
%$ if t(1)
%$    t(2) = dassert(x.vobs,1);
%$    t(3) = dassert(x.name{1},'u');
Stéphane Adjemian's avatar
Stéphane Adjemian committed
257
%$    t(4) = all(x.data(5:end)==2) && all(x.data(1:4)==1);
258 259 260
%$    t(5) = all(x.dates==dates('1989Q1'):dates('1990Q4'));
%$ end
%$ T = all(t);
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
%@eof:4

%@test:5
%$ % Define two dseries objects.
%$ y = dseries(ones(8,1),'1938Q4', 'u');
%$ z = dseries(NaN(8,1),'1938Q4', 'u');
%$
%$ % Inderectly call merge method via subsasgn.
%$ try
%$    y.u = z.u;
%$    t(1) = true;
%$ catch
%$    t = false;
%$ end
%$
%$ if t(1)
%$    t(2) = dassert(y.vobs, 1);
%$    t(3) = dassert(y.name{1}, 'u');
%$    t(4) = all(isnan(y.data));
%$    t(5) = dassert(y.nobs, z.nobs);
%$    t(6) = dassert(y.dates(1), z.dates(1));
%$ end
%$ T = all(t);
%@eof:5