Dynamic field reference for nested structures [duplicate] - matlab

This question already has answers here:
Dynamical access to nested fields in Matlab
(2 answers)
Closed 4 years ago.
In our MATLAB code, we've been using dynamic field references a lot, and they're pretty fantastic. We have a lot of different data structures with different field sets, so it makes it a whole lot easier to access any one of them simply using the struct.('field') notation, without having to use an eval statement.
However, where we run into problems is that many of these structures have multiple levels, and we don't always know how deep into the structure we will need to go. Ideally we'd like to be able to access them without using an eval statement, perhaps something like
struct.('field.field2.field3')
Is there a way to dynamically access structures with unknown depth using the builtin functionality? Or will we have to create a custom function for accessing all of our structures?

This code works for the following assumptions and usage cases:
There is a field that you do not know where it is within some nested dynamic structure.
The name of this field is unique, i.e. there is no other field anywhere in the struct with the same name.
The following function works:
function [fieldplace]=findfield(s,field)
% is one of these?
fieldplace={};
if (isfield(s,field))
fieldplace{end+1}=field;
return;
end
if ~isstruct(s)
fieldplace={};
return;
end
% otherwise is nested somewhere, use recursivity.
fnames=fieldnames(s);
for ii=1:numel(fnames)
fieldplace=findfield(s.(fnames{ii}),field);
if ~isempty(fieldplace)
fieldplace=[fnames{ii} fieldplace];
return;
end
end
end
Usage case:
s.a=1;
s.b.c=2;
s.b.d=3;
s.e.f.g=4;
s.h.i.j.k=5;
result=findfield(s,'k');
You can read the field as:
getfield(s,result{:})

Related

Collect internal variables of nested functions in matlab

I have a project consisting of multiple nested functions.
For debugging purpose I want to save all internal variables in one way or another, in order to display figures, replay parts of code etc...
I also want to keep this as transparent as possible regarding calculation time.
My first thought was to create a global variable, and store programmatically at the end of each function the inputs and outputs inside the variable as a structure :
globalVariable.nameOfParentfunction_NameOfFunction.nameInput1 = valueInput1;
globalVariable.nameOfParentfunction_NameOfFunction.nameInput2 = valueInput2;
...
globalVariable.nameOfParentfunction_NameOfFunction.nameOutput1 = valueOutput1;
...
Is it possible to use some kind of reflection to get the name and value of inputs/outputs without necessarily parse the file where the function is written?
I found a good but maybe outdated topic about parsing
How do I collect internal signals?
The simple solution is to use save, which will save all variables in the current workspace (the function’s context) to file.
If you want to keep the values in memory, not in a file, you can use names = who to get a list of all variables defined in the current workspace, then use val = eval(names{i}) to get the value of the variable called name{i}.
I would recommend putting all of that in a separate function, which you can call from any other function to store its variables, to avoid repeating code. This function would use evalin('caller',…) to get names and values of variables in the workspace of the calling function.
Note that using eval or evalin prevents MATLAB from optimizing code using its JIT. They also are dangerous to use, since they can execute arbitrary code, however in this case you control what is being executed so that is no a concern.

Exploit Matlab copy-on-write by ensuring function arguments are read-only?

Background
I'm planning to create a large number of Matlab table objects once, so that I can quickly refer to their contents repeatedly. My understanding is that each table variable/column is treated in copy-on-write manner. That is, if a table column is not modified by a function, then a new copy is not created.
From what I recall of C++ as of 1.5 decades ago, I could ensure that the code for a function does not modify its argument's data by using constant-correctness formalism.
The specific question
I am not using C++ in these days, but I would like to achieve a similar effect of ensuring that the code for my Matlab function doesn't change the data for selected arguments, either inadvertently or otherwise. Does anyone know of a nonburensome way to do this, or just as importantly, whether this is an unrealistic expectation?
I am using R2015b.
P.S. I've web searched and came across various relevant articles, e.g.:
http://www.mathworks.com/matlabcentral/answers/359410-is-it-possible-to-avoid-copy-on-write-behavior-in-functions-yet
http://blogs.mathworks.com/loren/2007/03/22/in-place-operations-on-data
(which I need clarification on to fully understand, but it isn't my priority just now)
However, I don't believe that I am prematurely optimizing. I know that I don't want to modify the tables. I just need a way to enforce that without having to go through contortions like creating a wrapper class.
I've posted this at:
* Stack Overflow
* Google groups
There is no way of making variables constants in MATLAB, except by creating a class with a constant (and static?) member variable. But even then you can do:
t = const_table_class.table;
t(1,1) = 0; % Created and modified a copy!
The reason that a function does not need to mark its inputs as const is because arguments are always passed by value. So a local modification does not modify data in the caller’s workspace. const is something that just doesn’t exist in the MATLAB language.
On the other hand, you can be certain that your data will not be modified by any of the functions you call. Thus, as long as the function that owns the tables does not modify them, they will remain constant. Any function you pass these tables to, if they attempt to modify them, they will create a local copy to be modified. This is only locally a problem. The memory used up by this copy will be freed upon function exit. It will be a bug in the function, but not affect code outside this function.
You can define a handle class that contains a table as it's preperty. Define a property set listener that triggers and generates error/warning when the value of the property changes.
classdef WarningTable < handle
properties (SetObservable)
t
end
methods
function obj = WarningTable(varargin)
obj.t = table(varargin);
addlistener(obj,'t','PreSet',...
#(a,b)warning('table changed!'));
end
end
end
This should generate warning:
mytable = WarningTable;
mytable.t(1,1) = 0;

Define variables in loops using loop indicies [duplicate]

I have a process which is repeated on a set of data stored in separate folders. Each time a certain folders data is processed I need new variable names as I need to results separate after the initial processing is finished for more processing.
For example at the start of each new block of the repeated function I declare sets of arrays
Set_1 = zeros(dim, number);
vectors_1 = zeros(dim, number);
For the next set of data I need:
`Set_2 = .........`
and so on. There is going to be alot of these sets so I need a way to automate the creation of these variables, and the use the new variables names in the function whilst maintaining that they are separate once all the functions are completed.
I first tried using strcat('Set_1',int2str(number)) = zeros(dim, number) but this does not work, I believe because it means I would be trying to set an array as a string. I'm sure there must be a way to create one function and have the variables dynamically created but it seems to be beyond me, so it's probably quite obvious, so if anyone can tell me a way that would be great.
I'd not do it like this. It's a bad habit, it's better to use a cell array or a struct to keep multiple sets. There is a small overhead (size-wise) per field, but it'll be a lot easier to maintain later on.
If you really, really want to do that use eval on the string you composed.
The MATLAB function genvarname does what you want. In your case it would look something like:
eval(genvarname('Set_', who)) = zeros(dim, number);
However, I would follow the recommendations of previous answers and use a cell or struct to store the results.
This sort of pattern is considered harmful since it requires the eval function. See one of the following for techniques for avoiding it:
http://www.mathworks.co.uk/support/tech-notes/1100/1103.html
http://blogs.mathworks.com/loren/2005/12/28/evading-eval/
If you insist on using eval, then use something like:
eval(sprintf('Set_1%d = zeros(dim, number);', number))

Built in function/ easy way to see if structure is a piecewise-polynomial?

Suppose I want a function that takes a variable as input and returns 1 if the variable is ppform and 0 if it isn't. Since ppforms in MATLAB are structures, but not all structures are ppform, I see no way to use isa to do this.
I could of course write a function to check if a given variable is a structure, has the right fields, and that the fields themselves are of the right form, but I'm just wondering if MATLAB has a built in function that can do this? Google and the MATHWORKS website have not helped me here.
Given your variable pp, you can check that it's a structure and has the appropriate fields:
isstruct(pp) & isequal(fields(pp), {'form' 'breaks' 'coefs' 'pieces' 'order' 'dim'}.')
Note that this doesn't check that the fields' contents are of the appropriate type (for example, the field form should contain a string) or have the permitted values.

dynamic variable names in matlab

I wish to expand a structure (bac) with a number of fields from another structure (BT). The names of these fields are contained in the cell array (adds) as strings.
this is what i have now (and obviously doesn't do the job, explaining this post):
for i=1:numel(adds)
eval(genvarname('bac.',adds{i})) = eval(strcat('BT.',adds{i}));
end
I also tried using sprintf, which did not seem to work for me. I feel confident one of you knows how to do it, since I feel it should be rather easy.
The best way of doing this is to use dynamic field names:
for i=1:numel(adds)
bac.(adds{i}) = BT.(adds{i});
end