dealing with nested struct access in MATLAB - matlab

What is the best way to avoid writing something like:
someDataStruct.longSubStructName.anotherLongName.theVariable = someStruct.longSubStructName.anotherLongName.theVariable + 10;
This is too verbose and doesn't look readable. What would be the best way to deal with this in Matlab without having any objects?

Purely for readability you might split this in a few lines.
someDataStruct.longSubStructName.anotherLongName.theVariable ...
= someStruct.longSubStructName.anotherLongName.theVariable ...
+ 10;
Or via a temp variable
tmp = someStruct.longSubStructName.anotherLongName.theVariable + 10;
someDataStruct.longSubStructName.anotherLongName.theVariable = tmp;
Matlab doesn't really support 'references' though, if that's what you're asking, (unless explicitly coded into a class by inheriting from the Handle class, but that's another story)
Obviously you can try hacks involving setfield / getfield and a sequence of objects, e.g. if you capture the 'route' to theVariable for each struct at least once:
Var1 = {someDataStruct, 'longSubStructName', 'anotherLongName', 'theVariable'};
Var2 = {someStruct, 'longSubStructName', 'anotherLongName', 'theVariable'};
then you can expand these in subsequent functional calls, e.g.
setfield( Var1{:}, getfield( Var2{:} ) + 10 )
but I'm not sure this is necessarily more readable tbh; it's just 'shorter'.
Equally, you might opt to create graphics objects instead of normal structs, which then do allow you to capture references to sub-objects and manipulate them directly ... but again, this probably causes more confusion in the end.
So, basically, just bite the bullet and use temporary variables.
It doesn't get any more readable than that in matlab. :)

According to matlab doc you can't access a nested struct without pass through all struct level. Maybe you can create a temp variable that starts from a middle level but is against the principle of matlab.
https://it.mathworks.com/help/matlab/matlab_prog/access-data-in-nested-structures.html

Just to add more possible syntax to your toolbox, this piece of code
someDataStruct.longSubStructName.anotherLongName.theVariable = 1;
someDataStruct.longSubStructName.anotherLongName.theVariable = ...
someDataStruct.longSubStructName.anotherLongName.theVariable + 10;
could equally be written as
n = {'longSubStructName','anotherLongName','theVariable'}; # names
someDataStruct.(n{1}).(n{2}).(n{3}) = 1;
someDataStruct.(n{1}).(n{2}).(n{3}) = someDataStruct.(n{1}).(n{2}).(n{3}) + 10;
Also; if you are using strings of uncertain origin as fieldnames (e.g. HDF5 attribute names which support spaces and some special characters which matlab structure field names do not), you can make sure they are valid with matlab.lang.makeValidName(fieldname).

Related

What is a maintainable way of trading collections of variables between functions?

I want to write a script experiment.m that will call a complicated function called encoder(...).
encoder will involve a lot of settings that experiment.m is going to choose at runtime.
At some point in experiment.m, the settings which encoder will use are created as variables (in this example there are two, in real life there can be dozens):
blocklength = [some derivation];
bitdepth = [some derivation];
I create a struct that stores these values under their names:
encoder_settings = struct();
encoder_settings.blocklength = blocklength;
encoder_settings.bitdepth = bitdepth;
And I write my encoder function like this:
function encoder_out = encoder(data, encoder_settings)
blocklength = encoder_settings.blocklength;
bitdepth = encoder_settings.bitdepth;
[...]
end
This works fine for code of moderate complexity, but after a while it becomes difficult to maintain the create-struct/load-struct blocks.
Alternatives I can think of don't seem great either:
encoder is usually very complex and calling the variables directly from the struct in its body makes the code difficult to read.
Do it dynamically using eval like this:
for s = fieldnames(my_struct)' eval([s{:},' = my_struct.', s{:}, ';']); end
I like using objects for this. But structs can work fine, too. Objects have the advantage that you can do input validation on their properties, too.
Use short names for the objects/structs themselves, and keep all your variables in objects in the calling function right off the bat, instead of storing them in plain local variables first and then copying them in to an object or struct for the transfer between the two functions.
And if you're using objects, you can make the functions be methods on your objects, to organize them further.

Matlab: Slicing matrix inside a containers.Map always requires intermediate referencing?

Prologue:
I am in the process of designing/prototyping a piece of code in Matlab.
As at the moment it is not clear to me which matrices should be returned by my functions, I chose, as a general approach, to bind my returned values in containers.Map (as I would do e.g. in python).
Hence, the general setting is
function output = myfoo(args)
output = containers.Map;
...some stuff
output('outname1') = ...
output('outname2') = ...
end
this approach should have the advantage of allowing me to add more returned data without messing up the other code too much or break backwards compatibility.
Issue:
How to deal in a elegant way with matrix slicing?
Say that I need to do something like
output('outname1')(2:end) = ...
(which gives an error as two indexes are not allowed and a boring workaround like
temp = output('outname1')
temp(2:end) = ...
output('outname1') = temp
is required).
Question:
Is there a proficient way to deal with this, avoiding all this referencing/copying job?
No, there is no way to do it without a temporary variable. The only case in which a double index is valid in Matlab is for a cell array. In that case, you can use
output{...}(...)
However, in any other case, a double index results in an error.

Can you call a matrix from a string

I have to make a call to read in a matrix with a name that is created from a strcat, in Matlab. For example
person = 2;
Index_XNY = strcat('Index_X',num2str(person),'Y');
Big_Index = find(Index_XNY(1,:)==1);
This works if I replace Index_XNY with Index_X2Y for this example.
I have tried a number of different things to obtain Big_Index, but so far I have not been successful. Can this be done, as there is a large collection of data elements that need to be called.
You can use the eval function to evaluate a Matlab expression in a string:
expr = strcat('find(Index_X',num2str(person),'Y(1,:)==1)');
Big_Index = eval(expr);
Of course, a lot of alternative ways to do this with eval function exist, depending on how much you would like to put into the string and how much would be left out.

matlab: is there a way to import/promote variables from a structure to the current workspace?

function y = myfunc(param)
C = param.C;
L = param.L;
Kp = param.Kp;
Ki = param.Ki;
...
Is there a way to generalize the above code? I know how to generalize the structure access using fieldnames() and getfield(), but not how to set variables without calling eval() (which is evil).
for n = fieldnames(param)'
name = n{1};
value = param.(name);
do_something_with(name,value); % ????
never mind, I figured it out; this helper function works:
function vars_pull(s)
for n = fieldnames(s)'
name = n{1};
value = s.(name);
assignin('caller',name,value);
end
The only way to create a variable whose name is determined at run-time is to use a function like eval, evalin, feval, or assignin. (assignin is the least evil choice BTW, at least you don't need to convert your value to a string and back.)
However, I question why you want to do that, why not just access the values through the input structure as you need them. If you want to save typing (speaking from experience, as I am extremely lazy), I usually name my input parameter structure something short, like p. The throughout my code I just access the fields directly, (e.g. p.Kp, and after a while I don't even see the p. anymore.) This also makes it easy to pass the structure into subfunctions as needed.
You can use the excellent submission at FileExchange:
V2STRUCT - Pack & Unpack variables to & from structures with enhanced functionality
Here's a workaround: save the structure to a .mat file using the '-struct' option, and then immediately reload it. Here's an example for struct variable X:
save('deleteme.mat','-struct','X');
load('deleteme.mat');
delete('deleteme.mat');
It's kludgey, but actually pretty fast, at least with an SSD.

Constants in MATLAB

I've come into ownership of a bunch of MATLAB code and have noticed a bunch of "magic numbers" scattered about the code. Typically, I like to make those constants in languages like C, Ruby, PHP, etc. When Googling this problem, I found that the "official" way of having constants is to define functions that return the constant value. Seems kludgey, especially because MATLAB can be finicky when allowing more than one function per file.
Is this really the best option?
I'm tempted to use / make something like the C Preprocessor to do this for me. (I found that something called mpp was made by someone else in a similar predicament, but it looks abandoned. The code doesn't compile, and I'm not sure if it would meet my needs.)
Matlab has constants now. The newer (R2008a+) "classdef" style of Matlab OOP lets you define constant class properties. This is probably the best option if you don't require back-compatibility to old Matlabs. (Or, conversely, is a good reason to abandon back-compatibility.)
Define them in a class.
classdef MyConstants
properties (Constant = true)
SECONDS_PER_HOUR = 60*60;
DISTANCE_TO_MOON_KM = 384403;
end
end
Then reference them from any other code using dot-qualification.
>> disp(MyConstants.SECONDS_PER_HOUR)
3600
See the Matlab documentation for "Object-Oriented Programming" under "User Guide" for all the details.
There are a couple minor gotchas. If code accidentally tries to write to a constant, instead of getting an error, it will create a local struct that masks the constants class.
>> MyConstants.SECONDS_PER_HOUR
ans =
3600
>> MyConstants.SECONDS_PER_HOUR = 42
MyConstants =
SECONDS_PER_HOUR: 42
>> whos
Name Size Bytes Class Attributes
MyConstants 1x1 132 struct
ans 1x1 8 double
But the damage is local. And if you want to be thorough, you can protect against it by calling the MyConstants() constructor at the beginning of a function, which forces Matlab to parse it as a class name in that scope. (IMHO this is overkill, but it's there if you want it.)
function broken_constant_use
MyConstants(); % "import" to protect assignment
MyConstants.SECONDS_PER_HOUR = 42 % this bug is a syntax error now
The other gotcha is that classdef properties and methods, especially statics like this, are slow. On my machine, reading this constant is about 100x slower than calling a plain function (22 usec vs. 0.2 usec, see this question). If you're using a constant inside a loop, copy it to a local variable before entering the loop. If for some reason you must use direct access of constants, go with a plain function that returns the value.
For the sake of your sanity, stay away from the preprocessor stuff. Getting that to work inside the Matlab IDE and debugger (which are very useful) would require deep and terrible hacks.
I usually just define a variable with UPPER_CASE and place near the top of the file. But you have to take the responsibly of not changing its value.
Otherwise you can use MATLAB classes to define named constants.
MATLAB doesn't have an exact const equivalent. I recommend NOT using global for constants - for one thing, you need to make sure they are declared everywhere you want to use them. I would create a function that returns the value(s) you want. You might check out this blog post for some ideas.
You might some of these answers How do I create enumerated types in MATLAB? useful. But in short, no there is not a "one-line" way of specifying variables whose value shouldn't change after initial setting in MATLAB.
Any way you do it, it will still be somewhat of a kludge. In past projects, my approach to this was to define all the constants as global variables in one script file, invoke the script at the beginning of program execution to initialize the variables, and include "global MYCONST;" statements at the beginning of any function that needed to use MYCONST. Whether or not this approach is superior to the "official" way of defining a function to return a constant value is a matter of opinion that one could argue either way. Neither way is ideal.
My way of dealing with constants that I want to pass to other functions is to use a struct:
% Define constants
params.PI = 3.1416;
params.SQRT2 = 1.414;
% Call a function which needs one or more of the constants
myFunction( params );
It's not as clean as C header files, but it does the job and avoids MATLAB globals. If you wanted the constants all defined in a separate file (e.g., getConstants.m), that would also be easy:
params = getConstants();
Don't call a constant using myClass.myconst without creating an instance first! Unless speed is not an issue. I was under the impression that the first call to a constant property would create an instance and then all future calls would reference that instance, (Properties with Constant Values), but I no longer believe that to be the case. I created a very basic test function of the form:
tic;
for n = 1:N
a = myObj.field;
end
t = toc;
With classes defined like:
classdef TestObj
properties
field = 10;
end
end
or:
classdef TestHandleObj < handle
properties
field = 10;
end
end
or:
classdef TestConstant
properties (Constant)
field = 10;
end
end
For different cases of objects, handle-objects, nested objects etc (as well as assignment operations). Note that these were all scalars; I didn't investigate arrays, cells or chars. For N = 1,000,000 my results (for total elapsed time) were:
Access(s) Assign(s) Type of object/call
0.0034 0.0042 'myObj.field'
0.0033 0.0042 'myStruct.field'
0.0034 0.0033 'myVar' //Plain old workspace evaluation
0.0033 0.0042 'myNestedObj.obj.field'
0.1581 0.3066 'myHandleObj.field'
0.1694 0.3124 'myNestedHandleObj.handleObj.field'
29.2161 - 'TestConstant.const' //Call directly to class(supposed to be faster)
0.0034 - 'myTestConstant.const' //Create an instance of TestConstant
0.0051 0.0078 'TestObj > methods' //This calls get and set methods that loop internally
0.1574 0.3053 'TestHandleObj > methods' //get and set methods (internal loop)
I also created a Java class and ran a similar test:
12.18 17.53 'jObj.field > in matlab for loop'
0.0043 0.0039 'jObj.get and jObj.set loop N times internally'
The overhead in calling the Java object is high, but within the object, simple access and assign operations happen as fast as regular matlab objects. If you want reference behavior to boot, Java may be the way to go. I did not investigate object calls within nested functions, but I've seen some weird things. Also, the profiler is garbage when it comes to a lot of this stuff, which is why I switched to manually saving the times.
For reference, the Java class used:
public class JtestObj {
public double field = 10;
public double getMe() {
double N = 1000000;
double val = 0;
for (int i = 1; i < N; i++) {
val = this.field;
}
return val;
}
public void setMe(double val) {
double N = 1000000;
for (int i = 1; i < N; i++){
this.field = val;
}
}
}
On a related note, here's a link to a table of NIST constants: ascii table and a matlab function that returns a struct with those listed values: Matlab FileExchange
I use a script with simple constants in capitals and include teh script in other scripts tr=that beed them.
LEFT = 1;
DOWN = 2;
RIGHT = 3; etc.
I do not mind about these being not constant. If I write "LEFT=3" then I wupold be plain stupid and there is no cure against stupidity anyway, so I do not bother.
But I really hate the fact that this method clutters up my workspace with variables that I would never have to inspect. And I also do not like to use sothing like "turn(MyConstants.LEFT)" because this makes longer statements like a zillion chars wide, making my code unreadible.
What I would need is not a variable but a possibility to have real pre-compiler constants. That is: strings that are replaced by values just before executing the code. That is how it should be. A constant should not have to be a variable. It is only meant to make your code more readible and maintainable. MathWorks: PLEASE, PLEASE, PLEASE. It can't be that hard to implement this. . .