Matlab coder & dynamic field references - matlab

I'm trying to conjure up a little parser that reads a .txt file containing parameters for an algorithm so i don't have to recompile it everytime i change a parameter. The application is C code generated from .m via coder, which unfortunately prohibits me from using a lot of handy matlab gimmicks.
Here's my code so far:
% read textfile
string = readfile(filepath);
% do fancy rearranging
linebreaks = zeros(size(string));
equals = zeros(size(string));
% find delimiters
for n=1:size(string,2)
if strcmp(string(n),char(10))
linebreaks(n) = 1;
elseif strcmp(string(n), '=')
equals(n) = 1;
end
end
% write first key-value pair
idx_s = find(linebreaks);idx_s = [idx_s length(string)];
idx_e = find(equals);
key = string(1:idx_e(1)-1);
value = str2double(string(idx_e(1)+1:idx_s(1)-1));
parameters.(key) = value;
% find number of parameters
count = length(idx_s);
% write remaining key-value pairs
for n=2:count
key = string(idx_s(n-1)+1:idx_e(n)-1);
value = str2double(string(idx_e(n)+1:idx_s(n)-1));
parameters.(key) = value;
end
The problem is that seemingly coder does not support dynamic fieldnames for structures like parameters.(key) = value.
I'm a bit at a loss as to how else i am supposed to come up with a parameter struct that holds all my key-value pairs without hardcoding it. It would somewhat (though not completely) defeat the purpose if the names of keys were not dynamically linked to the parameter file (more manual work if parameters get added/deleted, etc.). If anybody has an idea how to work around this, i'd be very grateful.

As you say, dynamic fieldnames for structures aren't allowed in MATLAB code to be used by Coder. I've faced situations much like yours before, and here's how I handled it.
First, we can list some nice tools that are allowed in Coder. We're allowed to have classes (value or handle), which can be quite handy. Also, we're allowed to have variable sized data if we use coder.varsize to specifically designate it. We also can use string values in switch statements if we like. However, we cannot use coder.varsize for properties in a class, but you can have varsized persistent variables if you like.
What I'd do in your case is create a handle class for storing and retrieving the values. The following example is pretty basic, but will work and could be expanded. If a persistent variable were used in a method, you could even create a varsized allocated storage for the data, but in my example, it's a property and has been limited in the number of values it can store.
classdef keyval < handle %# codegen
%KEYVAL A key and value class designed for Coder
% Stores an arbitrary number of keys and values.
properties (SetAccess = private)
numvals = 0
end
properties (Access = private)
intdata
end
properties (Constant)
maxvals = 100;
maxkeylength = 30;
end
methods
function obj = keyval
%KEYVAL Constructor for keyval class
obj.intdata = repmat(struct('key', char(zeros(1, obj.maxkeylength)), 'val', 0), 1, obj.maxvals);
end
function result = put(obj, key, value)
%PUT Adds a key and value pair into storage
% Result is 0 if successful, 1 on error
result = 0;
if obj.numvals >= obj.maxvals
result = 1;
return;
end
obj.numvals = obj.numvals + 1;
tempstr = char(zeros(1,obj.maxkeylength));
tempstr(1,1:min(end,numel(key))) = key(1:min(end, obj.maxkeylength));
obj.intdata(obj.numvals).key = tempstr;
obj.intdata(obj.numvals).value = value;
end
function keystring = getkeyatindex(obj, index)
%GETKEYATINDEX Get a key name at an index
keystring = deblank(obj.intdata(index).key);
end
function value = getvalueforkey(obj, keyname)
%GETVALUEFORKEY Gets a value associated with a key.
% Returns NaN if not found
value = NaN;
for i=1:obj.numvals
if strcmpi(keyname, deblank(obj.intdata(i).key))
value = obj.intdata(i).value;
end
end
end
end
end
This class implements a simple key/value addition as well as lookup. There are a few things to note about it. First, it's very careful in the assignments to make sure we don't overrun the overall storage. Second, it uses deblank to clear out the trailing zeros that are necessary in the string storage. In this situation, it's not permitted for the strings in the structure to be of different length, so when we put a key string in there, it needs to be exactly the same length with trailing nulls. Deblank cleans this up for the calling function.
The constant properties allocate the total amount of space we're allowed in the storage array. These can be increased, obviously, but not at runtime.
At the MATLAB command prompt, using this class looks like:
>> obj = keyval
obj =
keyval with properties:
numvals: 0
>> obj.put('SomeKeyName', 1.23456)
ans =
0
>> obj
obj =
keyval with properties:
numvals: 1
>> obj.put('AnotherKeyName', 34567)
ans =
0
>> obj
obj =
keyval with properties:
numvals: 2
>> obj.getvalueforkey('SomeKeyName')
ans =
1.2346
>> obj.getkeyatindex(2)
ans =
AnotherKeyName
>> obj.getvalueforkey(obj.getkeyatindex(2))
ans =
34567
If a totally variable storage area is desired, the use of persistent variables with coder.varsize would work, but that will limit the use of this class to a single instance. Persistent variables are nice, but you only get one of them ever. As written, you can use this class in many different places in your program for different storage. If you use a persistent variable, you may only use it once.
If you know some of the key names and are later using them to determine functionality, remember that you can switch on strings in MATLAB, and this works in Coder.

Related

Getters and Setters Within an Object

I have an object called TestData() that handles data processing and places it in a file in a specified format. One of the properties is data, which is stored as an array of type double. Here is the object and its constructor:
classdef TestData
properties
metaData = []; % stores meta data in Nx2 array
data = []; % stores data in PxQ array
colLabels = []; % labels columns
colUnits = []; % provides units
metaPrint % used to print metaData
temp % debugging purposes only
end
methods
%****************************************************************************%
%Function: TestData
%Purpose: Constructor used to allocate data arrays
%****************************************************************************%
function this = TestData() %constructor
this.metaPrint = [];
this.temp = [];
end %TestData()
The data that is placed into the object comes from a .m file external to the object, like so:
myTestData=TestData; % Generate an instance of the object
% Data
ErrorLine1 = zeros([length(ErrorLine')+2 1]); % Empty Vector to store 11X1
ErrorLine data
ErrorLine1(2:end-1) = ErrorLine(1:end);
mat = [Avec' Bvec' Invec' Ovec' ErrorLine1 PercentErrorOD'];
myTestData.data = mat;
So, when I set myTestData.data = mat this places the data in the object, but then calls the getter and setter functions for that object. One of the principle reasons for using these functions is to filter the data and determine if it is the correct type of data (in this case, the format would need to be double). When I try this in the code, however, it doesn't seem to work. Here is what I have written for the getter:
function data = get.data(this)
data = this.data;
end %getData
And the setter:
function this = set.data(this, data)
i = arrayfun(#(n)strcmp(class(this.data(n)), 'doube'), 1:numel(this.data)); %#ok<STISA>
disp(i)
if any(i == 0)
disp("WE HAVE A ZERO")
msg = "Data in object's 'data' property is not of type double";
error(msg);
else
this.data = data;
disp('Hi from setter')
end
end % set.data
If I run the strcmp and any functionality through the command window it works! When I run it from the editor, though, it always displays the "Hi from setter" string, even if I change "double" in the compare to "string." So, I am just not sure why it is not entering the if statement.
If there is anything that you can see in my code that could be modified to make it more efficient please let me know. Also, if there is anything else I can do my best. Thanks in advance!
In your setter, you have this line:
i = arrayfun(#(n)strcmp(class(this.data(n)), 'doube'), 1:numel(this.data));
But note that here you have not yet done this.data = data. When you test this.data, you test the old value of the property, not the value you want to assign. You need to test data.
Instead of using strcmp on the result of class, you can better test with isa. Furthermore, unless data is a cell array or a struct array, each of the elements will always be of the same class. You don't need to iterate over the whole array to test its type, just look at the type of the array itself. In the case of the cell array and the struct array, the indexing has to be different to extract elements. So, data(n) will always have the same type as data. Thus your setter can be written as:
function this = set.data(this, data)
if ~isa(data,'double')
error('WRONG!')
end
this.data = data;
end
Another issue with the code: if any(i == 0). any collapses one dimension of the input array. So if i is a 2D matrix, then the output is a row vector. Each element will be true if any of the elements in the given column is true. The if statement is only true if all elements of the given expression are nonzero. That means that all columns must have at least one 0 value for this expression to trigger.
Instead, do if any(i(:)==0). Here we make i into a column vector (this doesn't copy data, it's efficient), and thus any will return a single (scalar) value. If you have MATLAB R2018b, then you also do if any(i,'all'), which is equivalent.
You'll often see code doing if any(any(i==0)), but this fails if i happens to have three or more dimensions. It is also inefficient, the forms above are better.

Singleton registry class

I would like to create a singleton MATLAB class acting as a global registry. The registry should store objects (of a certain class derived from handle) addressed with unique names. I would like to access the properties of the stored classes conveniently without temporary variables, for example:
Registry.instance().addElement('name1', NewObject(...));
Registry.instance().get('name1').Value
Registry.instance().get('name2').Value = 1;
Reading out properties of the returned class can be circumvented by removing the () from instance:
>> Equipment.instance.get('name1').Value
However, it does not seem easy to use assignments because as noted in the comments, dot-indexing can't be used directly on the output of a function without assigning to an intermediate variable.
What is the proper way to implement and use such a "singleton registry" in MATLAB?
It should be noted that the singleton class contains some logic which is called when adding elements to the list, logic to properly destroy the objects in the right order and other methods which iterate through the object list. For that reason, a "normal" containers.Map cannot be used.
This might be what you're looking for:
classdef (Abstract) Registry % < handle <-- optional
methods (Access = public, Static = true)
function addElement(elementName, element)
Registry.accessRegistry('set', elementName, element );
end
function element = get(elementName)
element = Registry.accessRegistry('get', elementName);
end
function reset()
Registry.accessRegistry('reset');
end
end
methods (Access = private, Static = true)
function varargout = accessRegistry(action, fieldName, fieldValue)
% throws MATLAB:Containers:Map:NoKey
persistent elem;
%% Initialize registry:
if ~isa(elem, 'containers.Map') % meaning elem == []
elem = containers.Map;
end
%% Process action:
switch action
case 'set'
elem(fieldName) = fieldValue;
case 'get'
varargout{1} = elem(fieldName);
case 'reset'
elem = containers.Map;
end
end
end
end
Since MATLAB doesn't support static properties, one must resort to various workarounds, possibly involving methods with persistent variables, as is the case in my answer.
Here's a usage example of the above:
Registry.addElement('name1', gobjects(1));
Registry.addElement('name2', cell(1) ); % assign heterogeneous types
Registry.get('name1')
ans =
GraphicsPlaceholder with no properties.
Registry.get('name1').get % dot-access the output w/o intermediate assignment
struct with no fields.
Registry.get('name2'){1} % {}-access the output w/o intermediate assignment
ans =
[]
Registry.get('name3') % request an invalid value
Error using containers.Map/subsref
The specified key is not present in this container.
Error in Registry/accessRegistry (line 31)
varargout{1} = elem(fieldName);
Error in Registry.get (line 10)
element = Registry.accessRegistry('get', elementName);

MATLAB: Loop through the values of a list from 'who' function

I have a long list of variables in my workspace.
First, I'm finding the potential variables I could be interested in using the who function. Next, I'd like to loop through this list to find the size of each variable, however who outputs only the name of the variables as a string.
How could I use this list to refer to the values of the variables, rather than just the name?
Thank you,
list = who('*time*')
list =
'time'
'time_1'
'time_2'
for i = 1:size(list,1);
len(i,1) = length(list(i))
end
len =
1
1
1
If you want details about the variables, you can use whos instead which will return a struct that contains (among other things) the dimensions (size) and storage size (bytes).
As far as getting the value, you could use eval but this is not recommended and you should instead consider using cell arrays or structs with dynamic field names rather than dynamic variable names.
S = whos('*time*');
for k = 1:numel(S)
disp(S(k).name)
disp(S(k).bytes)
disp(S(k).size)
% The number of elements
len(k) = prod(S(k).size);
% You CAN get the value this way (not recommended)
value = eval(S(k).name);
end
#Suever nicely explained the straightforward way to get this information. As I noted in a comment, I suggest that you take a step back, and don't generate those dynamically named variables to begin with.
You can access structs dynamically, without having to resort to the slow and unsafe eval:
timestruc.field = time;
timestruc.('field1') = time_1;
fname = 'field2';
timestruc.(fname) = time_2;
The above three assignments are all valid for a struct, and so you can address the fields of a single data struct by generating the field strings dynamically. The only constraint is that field names have to be valid variable names, so the first character of the field has to be a letter.
But here's a quick way out of the trap you got yourself into: save your workspace (well, the relevant part) in a .mat file, and read it back in. You can do this in a way that will give you a struct with fields that are exactly your variable names:
time = 1;
time_1 = 2;
time_2 = rand(4);
save('tmp.mat','time*'); % or just save('tmp.mat')
S = load('tmp.mat');
afterwards S will be a struct, each field will correspond to a variable you saved into 'tmp.mat':
>> S
S =
time: 1
time_1: 2
time_2: [4x4 double]
An example writing variables from workspace to csv files:
clear;
% Writing variables of myfile.mat to csv files
load('myfile.mat');
allvars = who;
for i=1:length(allvars)
varname = strjoin(allvars(i));
evalstr = strcat('csvwrite(', char(39), varname, '.csv', char(39), ', ', varname, ')');
eval(evalstr);
end

Using a string to refer to a structure array - matlab

I am trying to take the averages of a pretty large set of data, so i have created a function to do exactly that.
The data is stored in some struct1.struct2.data(:,column)
there are 4 struct1 and each of these have between 20 and 30 sub-struct2
the data that I want to average is always stored in column 7 and I want to output the average of each struct2.data(:,column) into a 2xN array/double (column 1 of this output is a reference to each sub-struct2 column 2 is the average)
The omly problem is, I can't find a way (lots and lots of reading) to point at each structure properly. I am using a string to refer to the structures, but I get error Attempt to reference field of non-structure array. So clearly it doesn't like this. Here is what I used. (excuse the inelegence)
function [avrg] = Takemean(prefix,numslits)
% place holder arrays
avs = [];
slits = [];
% iterate over the sub-struct (struct2)
for currslit=1:numslits
dataname = sprintf('%s_slit_%02d',prefix,currslit);
% slap the average and slit ID on the end
avs(end+1) = mean(prefix.dataname.data(:,7));
slits(end+1) = currslit;
end
% transpose the arrays
avs = avs';
slits = slits';
avrg = cat(2,slits,avs); % slap them together
It falls over at this line avs(end+1) = mean(prefix.dataname.data,7); because as you can see, prefix and dataname are strings. So, after hunting around I tried making these strings variables with genvarname() still no luck!
I have spent hours on what should have been 5min of coding. :'(
Edit: Oh prefix is a string e.g. 'Hs' and the structure of the structures (lol) is e.g. Hs.Hs_slit_XX.data() where XX is e.g. 01,02,...27
Edit: If I just run mean(Hs.Hs_slit_01.data(:,7)) it works fine... but then I cant iterate over all of the _slit_XX
If you simply want to iterate over the fields with the name pattern <something>_slit_<something>, you need neither the prefix string nor numslits for this. Pass the actual structure to your function, extract the desired fields and then itereate them:
function avrg = Takemean(s)
%// Extract only the "_slit_" fields
names = fieldnames(s);
names = names(~cellfun('isempty', strfind(names, '_slit_')));
%// Iterate over fields and calculate means
avrg = zeros(numel(names), 2);
for k = 1:numel(names)
avrg(k, :) = [k, mean(s.(names{k}).data(:, 7))];
end
This method uses dynamic field referencing to access fields in structs using strings.
First of all, think twice before you use string construction to access variables.
If you really really need it, here is how it can be used:
a.b=123;
s1 = 'a';
s2 = 'b';
eval([s1 '.' s2])
In your case probably something like:
Hs.Hs_slit_01.data= rand(3,7);
avs = [];
dataname = 'Hs_slit_01';
prefix = 'Hs';
eval(['avs(end+1) = mean(' prefix '.' dataname '.data(:,7))'])

Sub-struct with dependent fields

In Matlab, I would like a data structure that looks like so:
DataStruct
.model
.Q
.Qchol
.
.
.system
.
.
The structure may well be a class, although I don't really need all the other functionality that goes with oop.
But I require
If Q is assigned something, then automatically Qchol = cholcov(Q).
If Qchol is assigned something, then automatically Q = Qchol' * Qchol.
Meanwhile, both Q and Qchol are stored for fast read-access
And Q and Qchol are writable through simple assignment, e.g.: DS1.mod.Q = value
I know I can make model a class, and have set/get methods for Q and Qchol. However, this really seems like an overkill for just two matrices (plus maybe some more fields). Also Matlab warns me that I should not access other properties during in a set method.
So: What is the best way to have such data structures, preferably without warnings?
You basically want assignment (DS1.mod.Q = value) to have side-effects, which inevitably implies a setter, and hence a class. You should either drop this requirement, or write a class.
If you wish to avoid definition of properties in the class declaration, you could use Dynamic Properties, which allows you to add properties at runtime (although with some telltale syntax addprop()).
EDIT
Patric, the problem goes deeper then just M-lint. Consider the following class:
classdef cantInstantiateMe < handle
properties
x
minus_x
end
methods
function obj = cantInstantiateMe(x)
obj.x = x; % <-- this calls set.x(), which calls set.minus_x(), which calls set.x(), ...
obj.minus_x = -x;
end
function set.x(obj, value)
obj.x = value;
obj.minus_x = -value; % <-- this gives an M-Lint warning
end
function set.minus_x(obj, value)
obj.minus_x = value;
obj.x = -value;
end
end
end
This class cannot be instantiated, because each setter calls the other setter (this is not Matlab-specific). Trying to instantiate on my machine gives:
??? Maximum recursion limit of 500 reached. Use set(0,'RecursionLimit',N)
to change the limit. Be aware that exceeding your available stack space can
crash MATLAB and/or your computer.
At this point I think you have two options:
Make either Q or Qchol a dependent property. This will come at the cost of re-calculating the dependent property each time you read-access it.
Use some private shadow properties e.g. shadow_Q and shadow_Qchol which will be set when the setter for the public property is called, and returned when their getter is called. Similar to:
function set.x(obj, value)
obj.shadow_x = value;
obj.shadow_minus_x = -value;
end
function value = get.x(obj)
value = obj.shadow_x;
end
Note the I did not test this properly, so I don't know all implications in Matlab. In other languages I'm familiar with, this should work fine.
Regarding the warning - my approach is that it is safe to disable the warning, as long as you really know what you are doing.
As suggested by #bavaza, one way to implement this is to use a dependent property with corresponding shadow private properties.
Below is the code implementing the inner data structure (inspired by this post). You need to use composition to make an instance of this class a property of the outer object:
classdef Model < handle
properties (Dependent)
Q
Qchol
end
properties (Access = private)
Q_
Qchol_
end
methods
function obj = Model()
end
function val = get.Q(obj)
val = obj.Q_;
end
function val = get.Qchol(obj)
val = obj.Qchol_;
end
function set.Q(obj, val)
obj.Q_ = val;
obj.Qchol_ = cholcov(val);
end
function set.Qchol(obj, val)
obj.Qchol_ = val;
obj.Q_ = val'*val;
end
end
end
Setting one value using the exposed dependent properties affects both underlying variables:
>> m = Model
m =
Model with properties:
Q: []
Qchol: []
>> m.Qchol = rand(3)
m =
Model with properties:
Q: [3x3 double]
Qchol: [3x3 double]