2 % Data Tree element which can be filtered by
'ids'
4 % The children branches of
this data tree node are all tagged with one or
7 % The branches can then be accessed via the
'id' argument of the get_index()
10 % Note: If one branch is tagged with a list of several
"Id"s, any of these
11 %
"Id"s in the last can be used to access the tagged branch.
13 properties (SetAccess =
private)
14 % cell array of
"Id" strings
19 % Data node type identifier
20 data_node_type =
'IdMap';
23 properties (Access =
private)
24 %
struct mapping between "Id"s and indices of children.
30 function ic =
IdMapNode(idmap, initvalues, mergefun)
31 %
function ic =
IdMapNode(idmap, initvalues, mergefun)
32 % constructor
for an
IdMapNode mapping the children nodes with
"Id" tags.
34 % This constructor can be run in two modes:
35 % -# @em Flat-mode: This creates exactly one
IdMapNode, such that
36 % it is possible that one child is tagged with more than one
"Id"
38 % -# @em Recursive-mode: This creates a tree of IdMapNode nodes,
39 % such that the leafs of
this tree are tagges with exactly one
"Id"
42 % The constructor runs in @em Flat-mode,
if a
'mergefun' is given or
if
43 %
'initvalues' is a cell array. Otherwise, it runs in @em Recursive-mode.
45 % @sa test_indexed_node() for example usage of this constructor.
47 % @note that the values given by 'initvalues' are wrapped by a
51 % idmap: a cell array of "Id" strings that are tagged to the
52 % children of this node. These "Id"s can also be nested,
53 % which either leads to a child tagged with more than one
54 % "Id"s or a recursively build tree of IdMapNode nodes.
55 % See the explanation of @em Flat-mode and @em
56 % Recursive-Mode for details.
57 % initvalues: This can be
63 % - In the first
case every child of
this node is set to
65 % - In the second
case the
'i'-th child is set to
67 % - In the third and fourth
case, a child tagged with
68 %
'id' is set to
'initvalues.(id)' respectively
69 %
'get(initvalues, get_index(initvalues, id, [], []))'.
70 % In @em Flat-mode, the
'mergefun' might apply here,
73 % mergefun: This is a
function pointer to a
function expecting a cell
74 % array of values as an argument and returning an arbitrary
76 % This
function pointer is used, in
case the constructor runs
77 % in @em Flat-mode and the initvalues are given as an
78 % IdMapNode or a
struct. For children tagged with several
79 %
"Id"s
'id1, ..., idn', mergefun can be used to compute a
80 % value
for this child from the cell array
81 %
'{initvalues.id1,..., initvalues.idn}'.
82 % If
'mergefun' is set to
'[]', a
default function
83 % @code @(x) x{1};
@endcode is used.
86 ic.values = cell(1, length(idmap));
88 if nargin == 2 && ~iscell(initvalues)
89 might_be_recursive = true;
91 might_be_recursive = false;
97 for i = 1:length(idmap)
105 for j = 1:length(idmapi)
106 ic.invmap.(idmapi{j}) = i;
109 ic.invmap.(idmap{i}) = i;
113 %
do we have initial values?
116 if iscell(initvalues)
117 assert(length(initvalues) == length(ic.values));
118 for i = 1:length(initvalues)
119 if isa(initvalues{i},
'DataTree.INode')
120 ic.values{i} = initvalues{i};
129 if ~isempty(initvalues)
130 set_values(ic, initvalues, mergefun);
134 set_values(ic, initvalues);
140 function data = get(this, index)
141 % function data = get(this, index)
146 data = get(this.values{index(1)}, index(2:end));
147 elseif length(index) == 1
148 if isa(this.values{index},
'DataTree.DummyLeafNode')
149 data =
get(this.values{index}, 1);
151 data = this.values{index};
160 function index = get_index(
this,
id, mu, nt)
161 %
function index = get_index(
this,
id, mu, nt)
165 %
id:
id string filtered by
this node or another IdMapNode instance.
167 % the tree hierarchy.
168 % nt: an integer corresponding to a time step index filtered through a
172 % index: index vector
for the element which is filter by the argument
173 % triple. If none such element exists, empty vector.
183 if isfield(this.invmap,
id)
184 invid = this.invmap.(
id);
185 index = [invid, get_index(this.values{invid}, id, mu, nt)];
191 %
function path = get_path_index(
this,
id, mu, nt)
192 % %
function path = get_path_index(
this,
id, mu, nt)
194 % path = get_index(
this,
id, mu, nt);
195 %
if ~this.recursive || iscell(this.idmap{path})
196 % path = [ path, get_path_index(this.values{path}, id, mu, nt) ];
200 function tree = create_tree(
this, creator, ids, mu_cube, tslice, basepath)
201 %
function tree = create_tree(
this, creator, ids, mu_cube, tslice, basepath)
206 % Calls DataTree.Creator.create_idmap_node() to build new elements.
221 % get possible indices for traversal
223 ids = fieldnames(this.invmap);
224 indices = 1:length(this);
226 ids=intersect(fieldnames(this.invmap), ids);
228 ids = fieldnames(this.invmap);
230 indices = unique(cellfun(@(x) this.invmap.(x), ids));
231 % indices = unique(cellfun(@(x) get_index(this, x, [], []), ids));
234 initvalues = cell(1, length(indices));
235 id_map = cell(1, length(indices));
236 for i=1:length(indices)
237 % compute
id intersection
238 new_id_extract = cellfun(@(x) this.invmap.(x)==indices(i), ids);
239 new_ids = ids(new_id_extract);
242 initvalues{i} = create_tree(
get(
this, indices(i)), creator, ...
243 new_ids, mu_cube, tslice, ...
244 [basepath, indices(i)]);
246 if length(indices) == 1
247 tree = initvalues{1};
248 elseif isempty(indices)
249 throw('Merge of trees failed, because given
id region was not found!');
251 tree = create_idmap_node(creator, id_map, initvalues);
255 function this = set(this, i, value, mergefun)
256 % function this = set(this, i, value[, mergefun])
257 % sets a new value at a specific child branch
259 % @note only direct children can be set.
262 % i: scalar index of the child to be set or vector of indices.
263 % In the latter case, set() is called recursively.
264 % value: a scalar, a struct or a tree of IdMapNode nodes as
265 % described in the constructor IdMapNode.IdMapNode().
266 % mergefun: (optional) If given, the function runs in @em Flat-mode as
267 % described in the constructor description IdMapNode.IdMapNode().
268 % Then 'value' needs to be a struct or a tree of IdMapNode
272 % this: handle to the changed IdMapNode.
275 this = set_values(this, value);
277 this = set_values(this, value, mergefun);
282 set(this.values{i(1)}, i(2:end), value)
284 set(this.values{i(1)}, i(2:end), value, mergefun)
286 elseif iscell(this.idmap{i})
288 this = set_values(this.values{i}, value);
290 this = set_values(this.values{i}, value, mergefun);
293 if isa(value,
'DataTree.INode')
294 this.values{i} = value;
301 function scalar = scalar(
this, mergefun)
302 %
function scalar = scalar(
this, mergefun)
303 % reduces the data tree values with help of the mergefun
306 % mergefun: This is a
function pointer to a
function expecting a cell
307 % array of values as an argument and returning an arbitrary
309 % For children tagged with several
"Id"s
'id1, ..., idn',
310 % mergefun can be used to compute a single value
for all thes
311 % children values. It gathers the values
312 %
'{ values1, ..., valuesn }' in a cell array and applies the
313 %
'mergefun' on it. The result is returned. The algorithm is
314 % run recursively, such that the
leaf-level is reduced first,
315 % and the upper level's values are reduced.
316 % If 'mergefun' is set to '[]', a default function
317 % @code @(x) x{1};
@endcode is used.
319 mergefun = @(x) x{1};
322 tmpcurvals = get_flat_struct(
this);
330 function ids = get_all_ids(
this)
331 %
function ids = get_all_ids(
this)
332 % returns all
"Id" strings in
this IdMapNode.
334 % @note that a flat cell array is returned, such that
this might unequal
338 % ids: a cell array of strings with the
"Id"s in
this data tree.
342 function st = get_flat_struct(
this)
343 %
function st = get_flat_struct(
this)
344 % makes a
struct from the data tree with field names equal to the "Id"
348 % st: flat
struct as described above
349 ids = get_all_ids(
this);
351 vals = cellfun(@(x)
get(
this, get_index(
this, x, [], [])), ids,
'UniformOutput',
false);
353 stcell = reshape([ids;vals], 1, 2*length(ids));
354 st =
struct(stcell{:});
357 function str = num2str(
this)
358 %
function str = num2str(
this)
359 % converts the data tree into a
string
362 % str: a
string representation of the data tree
363 fs = get_flat_struct(
this);
364 fns = fieldnames(fs);
366 for i = 1:length(fns)
367 str = [ str, fns{i},
': ', num2str(fs.(fns{i})) ];
375 function this = minus(this, scalar)
376 % function this = minus(this, scalar)
377 % substracts a scalar from each of the values in the data tree.
379 % This function assumes, that the IdMapNode has only
leaf children.
382 % scalar: The scalar to substract from the
leaf values.
385 % this: handle to the changed IdMapNode.
386 for i = 1:length(this.values)
387 assert(isa(this.values{i},
'DataTree.ILeafNode'));
393 function display(
this)
394 %
function display(
this)
395 % prints out a
string representation of the data tree.
396 disp(get_flat_struct(
this));
400 methods(Access =
private)
401 function this = set_values(this, values, mergefun)
402 % function this = set_values(this, values, mergefun)
403 % sets new values in the data tree.
406 % values: the new values. This can be either
407 % -
# a scalar substituting all values by this scalar,
408 % -# another tree of IdMapNode nodes or a struct, indicating which
409 % "Id" mapped values shall be set.
411 % this: handle to the current IdMapNode.
415 mergefun = @(x) x{1};
421 if isa(values,
'DataTree.IdMapNode')
422 values = get_flat_struct(values);
425 for i = 1:length(this.idmap)
427 if iscell(this.idmap{i})
429 set_values(this.values{i}, values);
436 error([
'Could not set values. Exception:, ' getReport(exception)]);
439 elseif isfield(values, fn)
442 this.values{i} = val;
448 elseif isscalar(values)
449 for i = 1:length(this.values)
452 elseif isempty(values)
453 warning('RBmatlab:Logic', 'Assigned nothing, because values argument is empty!');
455 error('Invalid assignment argument in method ''set_values''.');
460 methods(Static, Access = public)
462 function flatca = flatten_cell_array(ca)
463 % function flatca = flatten_cell_array(ca)
464 % flattens a cell array, i.e. returns a cell without cell entries which
465 % are cell arrays by itself.
471 % flatca: the flattended cell array
483 methods(Static, Access =
private)
485 function value = reduce(idmap, values, mergefun)
486 % function value = reduce(idmap, values, mergefun)
487 % Recursively reduces the
leaf values of the data tree to a scalar value
489 % This function recursively reduces the values.
492 % values: struct of values mapping "Id"s to values
493 % mergefun: function ptr assuming a cell of values as an argument.
494 % By default this is set to a function that returns the first
497 % value: scalar return by the 'mergefun'
499 mergefun = @(x) x{1};
501 tmpvals = cell(1, length(idmap));
502 for i = 1:length(idmap)
506 if ~isfield(values, idmap{i})
507 throw(MException(
'RBmatlab:IdMapNode:internal',[
'Values are missing the field: ', idmap{i}]));
509 val = values.(idmap{i});
510 if isa(val,
'DataTree.DummyLeafNode')
517 value = mergefun(tmpvals);
522 function idname = name_from_idmap(idmap)
523 % function idname = name_from_idmap(idmap)
524 % creates a
string representation of an "Id"-map
527 % idmap: a cell array of strings
530 % idname: a
string of all "Id"s concatenated with the '_' character.
532 tmp = unique(
DataTree.IdMapNode.flatten_cell_array(idmap));
533 idname = sprintf('%s_', tmp{:});
Data Tree element which can be filtered by ids
Dummy implementation for a DataTree.ILeafNode that stores a single data.
Interface for a node in a DataTree.
virtual function DataTree.INode tree = create_tree(DataTree.ICreator creator, ids, mu_cube, tslice, basepath)
Creates a new tree from a subtree specified by ids, parameter and time index regions.
Default implementation for a DataTree.INode.
virtual function index = get_index(id, mu, nt)
Obtains the leaf index vector that best fits the child description given by the three arguments...
Data Tree element which can be filtered by time instants.
static function flatca = flatten_cell_array(ca)
flattens a cell array, i.e. returns a cell without cell entries which are cell arrays by itself...