1function o = cumprod_(varargin) % --*-- Unitary tests --*--
2
3% Overloads matlab's cumprod function for dseries objects.
4%
5% INPUTS
6% - o     dseries object [mandatory].
7% - d     dates object [optional]
8% - v     dseries object with one observation [optional]
9%
10% OUTPUTS
11% - o     dseries object.
12
13% Copyright (C) 2014-2017 Dynare Team
14%
15% This file is part of Dynare.
16%
17% Dynare is free software: you can redistribute it and/or modify
18% it under the terms of the GNU General Public License as published by
19% the Free Software Foundation, either version 3 of the License, or
20% (at your option) any later version.
21%
22% Dynare is distributed in the hope that it will be useful,
23% but WITHOUT ANY WARRANTY; without even the implied warranty of
24% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25% GNU General Public License for more details.
26%
27% You should have received a copy of the GNU General Public License
28% along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
29
30% Get the firt observation number where all the variables are observed (ie without NaNs)
31idx = find(all(~isnan(varargin{1}.data), 2),1);
32if isempty(idx)
33    idx = 0;
34end
35
36% Is the first period where variables are observed common?
37common_first_period_witout_nan = true;
38if ~idx
39    if any(~isnan(varargin{1}.data(:)))
40        common_first_period_witout_nan = false;
41    end
42else
43    if idx>1
44        if any(any(~isnan(varargin{1}.data(1:idx-1,:))))
45            common_first_period_witout_nan = false;
46        end
47    end
48end
49
50switch nargin
51  case 1
52    % Initialize the output.
53    o = varargin{1};
54    % Perform the cumulated sum
55    if isequal(idx, 1)
56        o.data = cumprod(o.data);
57    else
58        if common_first_period_witout_nan
59            o.data(idx:end,:) = cumprod(o.data(idx:end,:));
60        else
61            o.data = cumprodnan(o.data);
62        end
63    end
64    for i=1:vobs(o)
65        if isempty(o.ops{i})
66            o.ops(i) = {['cumprod(' o.name{i} ')']};
67        else
68            o.ops(i) = {['cumprod(' o.ops{i} ')']};
69        end
70    end
71  case 2
72    if isdseries(varargin{2})
73        if ~isequal(vobs(varargin{1}), vobs(varargin{2}))
74            error('dseries::cumprod: First and second input arguments must be dseries objects with the same number of variables!')
75        end
76        if ~isequal(varargin{1}.name, varargin{2}.name)
77            warning('dseries::cumprod: First and second input arguments must be dseries objects do not have the same variables!')
78        end
79        if ~isequal(nobs(varargin{2}),1)
80            error('dseries::cumprod: Second input argument must be a dseries object with only one observation!')
81        end
82        o = cumprod_(varargin{1});
83        o.data = bsxfun(@rdivide, o.data, o.data(1,:));
84        o.data = bsxfun(@times, o.data, varargin{2}.data);
85    elseif isdates(varargin{2})
86        o = cumprod_(varargin{1});
87        t = find(o.dates==varargin{2});
88        if isempty(t)
89            if varargin{2}==(firstdate(o)-1)
90                return
91            else
92                error(['dseries::cumprod: date ' date2string(varargin{2}) ' is not in the sample!'])
93            end
94        end
95        o.data = bsxfun(@rdivide, o.data, o.data(t,:));
96    else
97        error('dseries::cumprod: Second input argument must be a dseries object or a dates object!')
98    end
99  case 3
100    if ~isdates(varargin{2})
101        error('dseries::cumprod: Second input argument must be a dates object!')
102    end
103    if ~isdseries(varargin{3})
104        error('dseries::cumprod: Third input argument must be a dseries object!')
105    end
106    if ~isequal(vobs(varargin{1}), vobs(varargin{3}))
107        error('dseries::cumprod: First and third input arguments must be dseries objects with the same number of variables!')
108    end
109    if ~isequal(varargin{1}.name, varargin{3}.name)
110        warning('dseries::cumprod: First and third input arguments must be dseries objects do not have the same variables!')
111    end
112    if ~isequal(nobs(varargin{3}),1)
113        error('dseries::cumprod: Third input argument must be a dseries object with only one observation!')
114    end
115    o = cumprod_(varargin{1});
116    t = find(o.dates==varargin{2});
117    if isempty(t)
118        if varargin{2}==(firstdate(o)-1)
119            o.data = bsxfun(@times, o.data, varargin{3}.data);
120            return
121        else
122            error(['dseries::cumprod: date ' date2string(varargin{2}) ' is not in the sample!'])
123        end
124    end
125    o.data = bsxfun(@rdivide, o.data, o.data(t,:));
126    o.data = bsxfun(@times, o.data, varargin{3}.data);
127  otherwise
128    error('dseries::cumprod: Wrong number of input arguments!')
129end
130
131%@test:1
132%$ % Define a data set.
133%$ A = 2*ones(4,1);
134%$
135%$ % Define names
136%$ A_name = {'A1'};
137%$
138%$ % Instantiate a time series object.
139%$ ts = dseries(A,[],A_name,[]);
140%$
141%$ % Call the tested method.
142%$ try
143%$     ts.cumprod_();
144%$     t(1) = 1;
145%$ catch
146%$     t(1) = 0;
147%$ end
148%$
149%$ if t(1)
150%$     t(2) = isequal(ts.data, cumprod(A));
151%$     t(3) = isequal(ts.name{1}, 'A1');
152%$     t(4) = isequal(ts.ops{1}, 'cumprod(A1)');
153%$ end
154%$
155%$ T = all(t);
156%@eof:1
157
158%@test:2
159%$ % Define a data set.
160%$ A = 2*ones(4,1);
161%$
162%$ % Define names
163%$ A_name = {'A1'};
164%$
165%$ % Instantiate a time series object.
166%$ ts = dseries(A,[],A_name,[]);
167%$
168%$ % Call the tested method.
169%$ try
170%$     cumprod_(ts);
171%$     t(1) = 1;
172%$ catch
173%$     t(1) = 0;
174%$ end
175%$
176%$ if t(1)
177%$     t(2) = isequal(ts.data, cumprod(A));
178%$     t(3) = isequal(ts.name{1},'A1');
179%$     t(4) = isequal(ts.ops{1}, 'cumprod(A1)');
180%$ end
181%$
182%$ T = all(t);
183%@eof:2
184
185
186%@test:3
187%$ % Define a data set.
188%$ A = 2*ones(7,1);
189%$
190%$ % Define names
191%$ A_name = {'A1'};
192%$
193%$ % Instantiate a time series object.
194%$ ts = dseries(A,[],A_name,[]);
195%$
196%$ % Call the tested method.
197%$ try
198%$   ts.cumprod_(dates('3Y'));
199%$   t(1) = 1;
200%$ catch
201%$   t(1) = 0;
202%$ end
203%$
204%$ % Expected results.
205%$ ds = dseries([.25; .5; 1; 2; 4; 8; 16], [], A_name, []);
206%$
207%$ % Check the results.
208%$ t(1) = dassert(ts.data, ds.data);
209%$ T = all(t);
210%@eof:3
211
212%@test:4
213%$ % Define a data set.
214%$ A = 2*ones(7,1);
215%$
216%$ % Define names
217%$ A_name = {'A1'};
218%$
219%$ % Instantiate a time series object.
220%$ ts1 = dseries(A, [], A_name, []);
221%$ ts2 = dseries(pi, [], A_name, []);
222%$
223%$ % Call the tested method.
224%$ try
225%$   ts3 = ts1.cumprod_(dates('3Y'), ts2);
226%$   t(1) = 1;
227%$ catch
228%$   t(1) = 0;
229%$ end
230%$
231%$ % Expected results.
232%$ ts4 = dseries([.25; .5; 1; 2; 4; 8; 16]*pi, [], A_name, []);
233%$
234%$ % Check the results.
235%$ if t(1)
236%$   t(2) = dassert(ts3.data,ts4.data);
237%$   t(3) = dassert(ts1.data,ts4.data);
238%$ end
239%$ T = all(t);
240%@eof:4
241
242%@test:5
243%$ % Define a data set.
244%$ A = 2*ones(7,1);
245%$
246%$ % Define names
247%$ A_name = {'A1'};
248%$
249%$ % Instantiate a time series object.
250%$ ts1 = dseries(A, [], A_name, []);
251%$ ts2 = dseries(pi, [], A_name, []);
252%$
253%$ % Call the tested method.
254%$ try
255%$   ts3 = ts1.cumprod_(dates('3Y'),ts2);
256%$   t(1) = 1;
257%$ catch
258%$   t(1) = 0;
259%$ end
260%$
261%$ % Expected results.
262%$ ts4 = dseries([.25; .5; 1; 2; 4; 8; 16]*pi, [], A_name, []);
263%$
264%$ % Check the results.
265%$ if t(1)
266%$   t(2) = dassert(ts3.data, ts4.data);
267%$   t(3) = dassert(ts1.data, ts4.data);
268%$ end
269%$ T = all(t);
270%@eof:5
271
272%@test:6
273%$ % Define a data set.
274%$ A = [NaN, NaN; 1 NaN; 1 1; 1 1; 1 NaN];
275%$
276%$ % Instantiate a time series object.
277%$ ts0 = dseries(A);
278%$
279%$ % Call the tested method.
280%$ try
281%$   ts0.cumprod_();
282%$   t(1) = 1;
283%$ catch
284%$   t(1) = 0;
285%$ end
286%$
287%$ % Check the results.
288%$ if t(1)
289%$   t(2) = dassert(ts0.data, A);
290%$ end
291%$ T = all(t);
292%@eof:6