IRootLab
An Open-Source MATLAB toolbox for vibrational biospectroscopy
block_cascade_base.m
Go to the documentation of this file.
1 %> @brief Cascade block: sequence of blocks represented by a block
2 %>
3 %> Cascade blocks can mimic the behaviour of linear transformation blocks (fcon_linear; such as PCA) if it contains one or more such blocks.
4 %> It has all the properties that a fcon_linear block has, however its valid functioning will depend on the component blocks.
5 %> The loadings matrix is calculated by multiplying the loadings matrix of successive component blocks.
6 %>
7 %>
8 %>
9 %> @arg boot: all component blocks booted
10 %> @arg train: after training first block, training data is inputted into it to get the training data to the second block etc
11 %> @arg use: output of (k-1)-th block is inputted into k-th block
12 %>
13 %>@sa uip_block_cascade_base.m, blsp_crossc
14 classdef block_cascade_base < block
15  properties
16  %> Cell of @c block objects
17  blocks = {};
18  %> =1. Whether to cross-calculate outputs when it is the case. The case is: in training; and the component block is level 1
19  %> (trainable); and the component block is not the last block. If @c flag_crossc is false, the same dataset will be used
20  %> to train and to calculate the block output.
21  flag_crossc = 0;
22  %> SGS to do the cross-calculations when necessary. If needed and empty, a default one will be used
23  sgs_crossc;
24  end;
25 
26 
27  % These properties have their getters and are read-only
28  properties
29  %> Loadings matrix. @ref fcon_linear mimicking. Calculates loadings matrix by multiplying
30  %> (<code>L = block1.L*block2.L*...</code>).
31  L;
32 % %> Feature names. @ref fcon_linear / fsel mimicking.
33 % fea_names;
34  %> Loadings feature names. @ref fcon_linear mimicking.
35  L_fea_names;
36  %> Feature x-axis. @ref fcon_linear mimicking. Retrieves the @c L_fea_x from the first block.
37  L_fea_x;
38  %> x-axis name. @ref fcon_linear mimicking. Retrieves the @c xname from the first block.
39  xname;
40  xunit;
41  yname;
42  yunit;
43  %> Class labels. @ref clssr mimicking. Retrieves the @c classlabels property from the last block.
44  classlabels;
45  %> Feature indexes. @ref fsel mimicking. Retrieves the @c v property from the last block.
46  v;
47  %> Decision threshold. @ref decider mimicking. Retriever the @c decisionthreshold property from some decider it finds along the
48  %> blocks
49  decisionthreshold;
50  end;
51  properties(SetAccess=protected)
52  %> Number of blocks.
53  no_blocks;
54  %> Whether the block is able to mimic a @ref fcon_linear. This is calculated at boot time.
55  flag_fcon_linear = 0;
56  %> Whether the block is able to mimic a @ref decider. This is calculated at boot time.
57  flag_decider = 0;
58  %> Index of first linear block. This is calculated at boot time.
59  idx_linear1;
60  %> Index of decider. This is calculated at boot time.
61  idx_decider;
62 
63  flag_checked = 0;
64  end;
65 
66  properties(Access=private)
67  %> Whether an error should be thrown if an invalid property is accessed. Because block_cascade_base can mimic several other classes,
68  %> but this is dependand on its component blocks, many properties can be invalid. However, giving errors all the time can be annoying
69  %> if the purpose is just to display properties, such as when one types the variable name at MATLAB command window.
70  %> If flag_give_error is false, all numeric properties will return a NaN when they are invalid
71  flag_give_error = 0;
72  end;
73 
74  methods
75  function o = block_cascade_base()
76  o.classtitle = 'Block Cascade';
77  o.short = 'Cascade';
78  o.flag_trainable = 1;
79  o.flag_bootable = 1;
80  end;
81 
82  function z = get.no_blocks(o)
83  z = length(o.blocks);
84  end;
85 
86  function L = get.L(o)
87  L = o.get_loadings();
88  end;
89 
90 % function z = get.fea_names(o)
91 % z = o.get_fea_names();
92 % end;
93 
94  function z = get.L_fea_x(o)
95  z = o.get_L_fea_x();
96  end;
97 
98  function z = get.xname(o)
99  z = o.get_xname();
100  end;
101 
102  function z = get.xunit(o)
103  z = o.get_xunit();
104  end;
105 
106  function z = get.yname(o)
107  z = o.get_yname();
108  end;
109 
110  function z = get.yunit(o)
111  z = o.get_yunit();
112  end;
113 
114  %> Other getters call yet another function, I don't know exactly why. I won't do this here because this may be
115  %> called many times.
116  function z = get.classlabels(o)
117  z = o.blocks{end}.classlabels;
118  end;
119 
120  %> Retrieves @c v from last block.
121  function z = get.v(o)
122  z = o.blocks{end}.v;
123  end;
124 
125  %> Retrieves @c decisionthreshold from the decider that if finds
126  function z = get.decisionthreshold(o)
127  if ~o.flag_decider
128  if o.flag_give_error
129  irerror('Cascade block cannot mimic a decider!');
130  else
131  z = NaN;
132  end;
133  else
134  z = o.blocks{o.idx_decider}.decisionthreshold;
135  end;
136  end;
137  end;
138 
139  methods
140  %> Extracts @ref fcon_linear_fixed with same Loadings Matrix
141  function blk = extract_fcon_linear_fixed(o)
142  blk = fcon_linear_fixed();
143  blk.L = o.L;
144  blk.copy_axes_from(o);
145  end;
146  end;
147 
148 
149 
150 
151 
152  %---------------------------------------------------------------------------------------------------------
153 
154  % GET EVERYTHING
155 
156  methods
157  function z = get_L_fea_x(o)
158  if numel(o.blocks) == 0
159  if o.flag_give_error
160  irerror('Cascade block is empty!');
161  else
162  z = NaN;
163  end;
164  else
165  if ~o.flag_fcon_linear
166  if o.flag_give_error
167  irerror('Cascade block cannot mimic a linear block!');
168  else
169  z = NaN;
170  end;
171  else
172  b = o.get_linear1();
173  z = b.L_fea_x;
174  end;
175  end;
176  end;
177 
178  function z = get_xname(o)
179  if numel(o.blocks) == 0
180  if o.flag_give_error
181  irerror('Cascade block is empty!');
182  else
183  z = '';
184  end;
185  else
186  if ~o.flag_fcon_linear
187  if o.flag_give_error
188  irerror('Cascade block cannot mimic a linear block!');
189  else
190  z = '';
191  end;
192  else
193  b = o.get_linear1();
194  z = b.xname;
195  end;
196  end;
197  end;
198 
199 
200  %> Feature names: takes the xname property from the first linear block
201  function z = get_xunit(o)
202  if numel(o.blocks) == 0
203  if o.flag_give_error
204  irerror('Cascade block is empty!');
205  else
206  z = '';
207  end;
208  else
209  if ~o.flag_fcon_linear
210  if o.flag_give_error
211  irerror('Cascade block cannot mimic a linear block!');
212  else
213  z = '';
214  end;
215  else
216  b = o.get_linear1();
217  z = b.xunit;
218  end;
219  end;
220  end;
221 
222  %> y-name: takes the yname property from the last block that has it
223  %>
224  %> @return yname. Defaults to an empty string.
225  function z = get_yname(o)
226  z = '';
227  for i = numel(o.blocks):-1:1
228  if isprop(o.blocks{i}, 'yname')
229  z = o.blocks{i}.yname;
230  break;
231  end;
232  end;
233  end;
234 
235  %> y-unit: takes the yunit property from the last block that has it
236  %>
237  %> @return yunit. Defaults to an empty string.
238  function z = get_yunit(o)
239  z = '';
240  for i = numel(o.blocks):-1:1
241  if isprop(o.blocks{i}, 'yunit')
242  z = o.blocks{i}.yunit;
243  break;
244  end;
245  end;
246  end;
247 
248 %
249 % %> Feature names: takes the fea_names property from the first linear block
250 % function z = get_fea_names(o)
251 % if numel(o.blocks) == 0
252 % if o.flag_give_error
253 % irerror('Cascade block is empty!');
254 % else
255 % z = {};
256 % end;
257 % else
258 % b = o.get_linear1();
259 % z = b.fea_names;
260 % end;
261 % end;
262 
263  %> @brief Calls get_methodname() for all blocks
264  %> @param flag_short=0
265  function s = get_methodname(o, flag_short)
266  if nargin < 2 || isempty(flag_short)
267  flag_short = 0;
268  end;
269  s = '';
270  for i = 1:length(o.blocks)
271  if i > 1
272  s = [s '->'];
273  end;
274  b = o.blocks{i};
275  s = [s b.get_methodname(flag_short)];
276  end;
277  end;
278 
279 
280  %> Mimicking a fcon_linear::get_L_fea_names()
281  %>
282  %> Calls the get_L_fea_names from the first block that has this method (SEARCHING BACKWARDS)
283  function a = get_L_fea_names(o, idxs)
284  a = {};
285  nb = numel(o.blocks);
286  if nb == 0
287  if o.flag_give_error
288  irerror('Cascade block is empty!');
289  else
290  end;
291  else
292  for i = nb:-1:1
293  b = o.blocks{i};
294  if ismethod(b, 'get_L_fea_names')
295  a = b.get_L_fea_names(idxs);
296  break;
297  end;
298  end;
299  end;
300  end;
301 
302 
303  %> Cascades blocks' loadings matrices. Works only if one or all blocks provide one loadings matrix of course, i.e., they
304  %> all represent linear transforms.
305  function L = get_loadings(o)
306  if ~o.flag_fcon_linear
307  if o.flag_give_error
308  irerror('Cascade block cannot mimic a linear block!');
309  else
310  L = NaN;
311  end;
312  else
313  if ~o.flag_trained
314  L = [];
315  else
316  for i = o.idx_linear1:length(o.blocks)
317  if ~ismember(properties(o.blocks{i}), 'L')
318  irerror(sprintf('Block ''%s'' does not have property ''L''!', o.blocks{i}.classtitle));
319  end;
320 
321  if i == o.idx_linear1
322  L = o.blocks{i}.L;
323  else
324  L = L*o.blocks{i}.L;
325  end;
326  end;
327  end;
328  end;
329  end;
330  end;
331 
332 
333 
334 
335 
336 
337 
338 
339  %---------------------------------------------------------------------------------------------------------
340 
341 
342  methods(Access=protected)
343  %> BLock needs to keep up-to-date with contents
344  function o = assert_checked(o)
345  if ~o.flag_checked
346  o = o.do_check();
347  end;
348  end;
349 
350  function o = do_check(o)
351  idx1temp = 0; % Index of first linear block
352  flag_cannot = 0; % Cannot be a linear block
353  o.flag_decider = 0;
354  level = 0;
355  for i = 1:length(o.blocks)
356  if isa(o.blocks{i}, 'block_cascade_base')
357  o.blocks{i} = o.blocks{i}.do_check();
358  end;
359 
360  if isa(o.blocks{i}, 'fcon_linear') || isa(o.blocks{i}, 'block_cascade_base') && o.blocks{i}.flag_fcon_linear
361  if idx1temp == 0
362  idx1temp = i;
363  end;
364  elseif idx1temp
365  flag_cannot = 1;
366  end;
367 
368  if ~o.flag_decider && isa(o.blocks{i}, 'decider')
369  o.flag_decider = 1;
370  o.idx_decider = i;
371  end;
372 
373  level = max(level, o.blocks{i}.flag_trainable);
374  end;
375 
376  o.flag_fcon_linear = ~flag_cannot && idx1temp > 0;
377  if o.flag_fcon_linear
378  o.idx_linear1 = idx1temp;
379  end;
380 
381  o.flag_trainable = level;
382 
383  o.flag_checked = 1;
384  end;
385 
386  %> Boots every encapsulated block
387  function o = do_boot(o)
388  o = o.do_check();
389 
390  for i = 1:length(o.blocks)
391  o.blocks{i} = o.blocks{i}.boot();
392  end;
393  end;
394 
395  %> Trains every encapsulated block
396  %> @todo think about stacked generalization
397  function o = do_train(o, data)
398  o = o.assert_checked();
399 
400  flag_crossc_first = 1;
401 
402  for i = 1:o.no_blocks
403  % Sequence here is cross-calculate; train; use.
404  %
405  % Cross-calculate and use are mutually exclusive.
406  %
407  % Note that cross-calculation could go after but I put it before to make it more robust to blocks that don't boot propertly
408 
409  % Cross-calculate
410  if i < o.no_blocks && o.flag_crossc && o.blocks{i}.flag_trainable > 0
411  % Creates block blsp_crossc if it is the first time the cross-calculated will be performed in this training function
412  if flag_crossc_first
413  block_crossc = blsp_crossc();
414  if ~isempty(o.sgs_crossc)
415  block_crossc.sgs = o.sgs_crossc;
416  end;
417  flag_crossc_first = 0;
418  end;
419 
420  block_crossc.mold = o.blocks{i};
421  data_next = block_crossc.use(data);
422  end;
423 
424  % Train
425  if o.blocks{i}.flag_trainable > 0
426  o.blocks{i} = o.blocks{i}.train(data);
427  end;
428 
429  % Use
430  if i < o.no_blocks && (~o.flag_crossc || o.blocks{i}.flag_trainable == 0)
431  data_next = o.blocks{i}.use(data);
432  end;
433 
434  if i < o.no_blocks
435  data = data_next;
436  end;
437  end;
438  end;
439 
440  %> output of (k-1)-th block is inputted into k-th block. Final output is the output of the end-th block.
441  %>
442  %> Skips any blmisc_rowsout block (outlier remover)
443  function data = do_use(o, data)
444  o = o.assert_checked();
445 
446  for i = 1:length(o.blocks)
447  blk = o.blocks{i};
448  if isa(blk, 'blmisc_rowsout')
449  % Skips outlier removers in use stage
450  else
451  data = o.blocks{i}.use(data);
452  end;
453  end;
454  end;
455 
456  %> Makes sure that the block can mimic a linear block
457  function o = assert_fcon_linear(o)
458  if ~o.flag_fcon_linear
459  irerror('Cascade block cannot mimic a linear block!');
460  end;
461  end;
462 
463 
464 % % % % % % % %> Makes sure that the block can mimic a linear block
465 % % % % % % % function o = assert_decider_(o)
466 % % % % % % % if ~o.flag_decider
467 % % % % % % % irerror('Cascade block cannot mimic a decider!');
468 % % % % % % % end;
469 % % % % % % % end;
470 
471  %> Retrieves the first linear block
472  function b = get_linear1(o)
473  o = o.assert_checked();
474 
475  o.assert_fcon_linear();
476  b = o.blocks{o.idx_linear1};
477  end;
478 
479  %>
480  function s = do_get_report(o)
481  s = do_get_report@block(o);
482 
483  len = length(o.blocks);
484  for i = 1:len
485  stemp = sprintf('Component Block %d/%d', i, len);
486  stemp2 = repmat('-', 1, length(stemp));
487  s = cat(2, s, sprintf('\n\n /%s\\\n| %s |\n \\%s/\n', stemp2, stemp, stemp2), o.blocks{i}.get_report());
488  end;
489  end;
490  end;
491 end
492 
493 
Feature Construction - Linear Transformations base class.
Definition: fcon_linear.m:2
Base Sub-dataset Generation Specification (SGS) class.
Definition: sgs.m:6
Outlier Removal base class.
Property decisionthreshold
=0. Minimum maximum probability. If not reached, assigned class will be -1, which means "refuse-to-de...
Definition: decider.m:16
Feature Selection (FSel) class.
Definition: fsel.m:4
function get_L_fea_names(in o, in idxs)
function irerror(in s)
Property classlabels
Class labels. clssr mimicking. Retrieves the classlabels property from the last block.
Block that resolves estimato posterior probabilities into classes.
Definition: decider.m:10
function use(in o, in data)
Applies block to data.
Base Block class.
Definition: block.m:2
Classifiers base class.
Definition: clssr.m:6
Loadings vector specified directly.
Analysis Session (AS) base class.
Definition: as.m:6
function uip_block_cascade_base(in varargin)
Cascade block: sequence of blocks represented by a block.