1function q = merge(o, p, legacy) % --*-- Unitary tests --*-- 2 3% Merge method for dseries objects. 4% 5% INPUTS 6% - o [dseries] 7% - p [dseries] 8% - legacy [logical] revert to legacy behaviour if `true` (default is `false`), 9% 10% OUTPUTS 11% - q [dseries] 12% 13% REMARKS 14% If dseries objects o and p have common variables, the variables 15% in p take precedence except if p has NaNs (the exception can be 16% removed by setting the third argument, legacy, equal to true). 17 18% Copyright © 2013-2020 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 35if ~isdseries(p) || ~isdseries(o) 36 error('dseries::merge: Both inputs must be dseries objects!') 37end 38 39if isempty(o) && ~isempty(p) 40 q = p; 41 return 42elseif ~isempty(o) && isempty(p) 43 q = o; 44 return 45elseif isempty(o) && isempty(p) 46 q = p; 47 return 48end 49 50if nargin<3 51 legacy = false; 52end 53 54if ~isequal(frequency(o), frequency(p)) 55 if isempty(inputname(1)) 56 error('dseries::merge: Cannot merge dseries objects (frequencies are different)!') 57 else 58 error(['dseries::merge: Cannot merge ' inputname(1) ' and ' inputname(2) ' (frequencies are different)!']) 59 end 60end 61 62q = dseries(); 63 64[q.name, IBC, ~] = unique([o.name; p.name], 'last'); 65 66if ~legacy 67 [list_of_common_variables, iO, iP] = intersect(o.name, p.name); 68end 69 70tex = [o.tex; p.tex]; 71q.tex = tex(IBC); 72 73ops = [o.ops; p.ops]; 74q.ops = ops(IBC); 75 76otagnames = fieldnames(o.tags); 77ptagnames = fieldnames(p.tags); 78qtagnames = union(otagnames, ptagnames); 79if isempty(qtagnames) 80 q.tags = struct(); 81else 82 for i=1:length(qtagnames) 83 if ismember(qtagnames{i}, otagnames) && ismember(qtagnames{i}, ptagnames) 84 q.tags.(qtagnames{i}) = vertcat(o.tags.(otagnames{i}), p.tags.(ptagnames{i})); 85 elseif ismember(qtagnames{i}, otagnames) 86 q.tags.(qtagnames{i}) = vertcat(o.tags.(qtagnames{i}), cell(vobs(p), 1)); 87 elseif ismember(qtagnames{i}, ptagnames) 88 q.tags.(qtagnames{i}) = vertcat(cell(vobs(o), 1), p.tags.(qtagnames{i})); 89 else 90 error('dseries::horzcat: This is a bug!') 91 end 92 q.tags.(qtagnames{i}) = q.tags.(qtagnames{i})(IBC); 93 end 94end 95 96if nobs(o) == 0 97 q = copy(p); 98elseif nobs(p) == 0 99 q = copy(o); 100elseif firstdate(o) >= firstdate(p) 101 diff = firstdate(o) - firstdate(p); 102 q_nobs = max(nobs(o) + diff, nobs(p)); 103 q.data = NaN(q_nobs, vobs(q)); 104 Z1 = [NaN(diff, vobs(o)); o.data]; 105 if nobs(q) > nobs(o) + diff 106 Z1 = [Z1; NaN(nobs(q)-(nobs(o) + diff), vobs(o))]; 107 end 108 Z2 = p.data; 109 if nobs(q) > nobs(p) 110 Z2 = [Z2; NaN(nobs(q) - nobs(p), vobs(p))]; 111 end 112 Z = [Z1 Z2]; 113 q.data = Z(:,IBC); 114 if ~legacy 115 if ~isempty(list_of_common_variables) 116 for i=1:length(iP) 117 jO = iO(i); 118 jP = iP(i); 119 jQ = find(strcmp(o.name{jO}, q.name)); 120 id = isnan(q.data(:,jQ)) & ~isnan(Z1(:,jO)) & isnan(Z2(:,jP)); 121 q.data(id, jQ) = Z1(id,jO); 122 end 123 end 124 end 125 q_init = firstdate(p); 126else 127 diff = firstdate(p) - firstdate(o); 128 q_nobs = max(nobs(p) + diff, nobs(o)); 129 q.data = NaN(q_nobs, vobs(q)); 130 Z1 = [NaN(diff, vobs(p)); p.data]; 131 if nobs(q) > nobs(p) + diff 132 Z1 = [Z1; NaN(nobs(q)-(nobs(p) + diff), vobs(p))]; 133 end 134 Z2 = o.data; 135 if nobs(q) > nobs(o) 136 Z2 = [Z2; NaN(nobs(q) - nobs(o), vobs(o))]; 137 end 138 Z = [Z2 Z1]; 139 q.data = Z(:,IBC); 140 if ~legacy 141 if ~isempty(list_of_common_variables) 142 for i=1:length(iP) 143 jO = iO(i); 144 jP = iP(i); 145 jQ = find(strcmp(o.name{jO}, q.name)); 146 id = isnan(q.data(:,jQ)) & isnan(Z1(:,jP)) & ~isnan(Z2(:,jO)); 147 q.data(id, jQ) = Z2(id,jO); 148 end 149 end 150 end 151 q_init = firstdate(o); 152end 153 154q.dates = q_init:q_init+(nobs(q)-1); 155 156%@test:1 157%$ % Define a datasets. 158%$ A = rand(10,2); B = randn(10,1); 159%$ 160%$ % Define names 161%$ A_name = {'A1';'A2'}; B_name = {'A1'}; 162%$ 163%$ % Instantiate two time series objects and merge. 164%$ try 165%$ ts1 = dseries(A,[],A_name,[]); 166%$ ts1.tag('type'); 167%$ ts1.tag('type', 'A1', 'Stock'); 168%$ ts1.tag('type', 'A2', 'Flow'); 169%$ ts2 = dseries(B,[],B_name,[]); 170%$ ts2.tag('type'); 171%$ ts2.tag('type', 'A1', 'Flow'); 172%$ ts3 = merge(ts1,ts2); 173%$ t(1) = true; 174%$ catch 175%$ t = false; 176%$ end 177%$ 178%$ if t(1) 179%$ t(2) = dassert(ts3.vobs,2); 180%$ t(3) = dassert(ts3.nobs,10); 181%$ t(4) = dassert(ts3.data,[B, A(:,2)],1e-15); 182%$ t(5) = dassert(ts3.tags.type, {'Flow';'Flow'}); 183%$ end 184%$ T = all(t); 185%@eof:1 186 187%@test:2 188%$ % Define a datasets. 189%$ A = rand(10,2); B = randn(10,1); 190%$ 191%$ % Define names 192%$ A_name = {'A1';'A2'}; B_name = {'B1'}; 193%$ 194%$ % Instantiate two time series objects and merge them. 195%$ try 196%$ ts1 = dseries(A,[],A_name,[]); 197%$ ts1.tag('t1'); 198%$ ts1.tag('t1', 'A1', 'Stock'); 199%$ ts1.tag('t1', 'A2', 'Flow'); 200%$ ts2 = dseries(B,[],B_name,[]); 201%$ ts2.tag('t2'); 202%$ ts2.tag('t2', 'B1', 1); 203%$ ts3 = merge(ts1,ts2); 204%$ t(1) = true; 205%$ catch 206%$ t = false; 207%$ end 208%$ 209%$ if length(t)>1 210%$ t(2) = dassert(ts3.vobs,3); 211%$ t(3) = dassert(ts3.nobs,10); 212%$ t(4) = dassert(ts3.data,[A, B],1e-15); 213%$ t(5) = dassert(ts3.tags.t1, {'Flow';'Flow';[]}); 214%$ t(6) = dassert(ts3.tags.t2, {[];[];1}); 215%$ end 216%$ T = all(t); 217%@eof:2 218 219%@test:3 220%$ % Define two dseries objects. 221%$ y = dseries(ones(4,1),'1989Q1', 'u'); 222%$ z = dseries(2*ones(4,1),'1990Q1', 'u'); 223%$ 224%$ % Merge the two objects. 225%$ try 226%$ x = merge(y, z); 227%$ t(1) = true; 228%$ catch 229%$ t = false; 230%$ end 231%$ 232%$ if t(1) 233%$ t(2) = dassert(x.vobs,1); 234%$ t(3) = dassert(x.name{1},'u'); 235%$ t(4) = all(x.data(5:end)==2) && all(x.data(1:4)==1); 236%$ t(5) = all(x.dates==dates('1989Q1'):dates('1990Q4')); 237%$ end 238%$ T = all(t); 239%@eof:3 240 241%@test:4 242%$ % Define two dseries objects. 243%$ y = dseries(ones(4,1),'1989Q1', 'u'); 244%$ z = dseries([NaN(4,1); 2*ones(4,1)],'1989Q1', 'u'); 245%$ 246%$ % Merge the two objects. 247%$ try 248%$ x = merge(y, z); 249%$ t(1) = true; 250%$ catch 251%$ t = false; 252%$ end 253%$ 254%$ if t(1) 255%$ t(2) = dassert(x.vobs,1); 256%$ t(3) = dassert(x.name{1},'u'); 257%$ t(4) = all(x.data(5:end)==2) && all(x.data(1:4)==1); 258%$ t(5) = all(x.dates==dates('1989Q1'):dates('1990Q4')); 259%$ end 260%$ T = all(t); 261%@eof:4 262 263%@test:5 264%$ % Define two dseries objects. 265%$ y = dseries(ones(8,1),'1938Q4', 'u'); 266%$ z = dseries(NaN(8,1),'1938Q4', 'u'); 267%$ 268%$ % Inderectly call merge method via subsasgn. 269%$ try 270%$ y.u = z.u; 271%$ t(1) = true; 272%$ catch 273%$ t = false; 274%$ end 275%$ 276%$ if t(1) 277%$ t(2) = dassert(y.vobs, 1); 278%$ t(3) = dassert(y.name{1}, 'u'); 279%$ t(4) = all(isnan(y.data)); 280%$ t(5) = dassert(y.nobs, z.nobs); 281%$ t(6) = dassert(y.dates(1), z.dates(1)); 282%$ end 283%$ T = all(t); 284%@eof:5