matlab with classes - save struct in empty double array - matlab

I try to create a class in matlab
It has a property children
properties
children
If this variable is written to - it is supposed to be an arrays of structs
it fails with
function obj = Init(obj, valueList)
%INIT Initialise with vector of new parameter sets
newSet = obj.ParamSet;
newSet.values = valueList;
obj.children(end + 1) = newSet; % <<< error
Error is :
Conversion to double from struct is not possible.
This is the struct that is used
methods(Static)
function paramset = ParamSet()
newset.('values') = [];
newset.('fitness') = 0;
paramset = newset;
end
end

The simple solution is to assign if it’s empty:
if isempty(obj.children)
obj.children = newSet;
else
obj.children(end + 1) = newSet;
end

Related

MatLab - accessing variables after a function is done with them

I'm new to MatLab and having difficulties using the results of my functions.
My program loads a .mat file as an object, and then for each variable in the .mat, it runs an analysis. The actual analysis is done by a function called in the for loop. The results of the analysis are stored by the function in an array - or they should be! As follows:
function main()
object = matfile('data.mat')
vars = (fieldnames(object))
resultarray = zeros(length(vars))
for index = 1:length(vars)
var = vars(index)
x = object.var
resultarray = analysis(x, index)
end
end
function resultarray = analysis(x, index)
%does stuff to x
resultarray(index) = x
disp(resultarray(index))
end
The problem is - none of my variables are visible! The workspace is empty. The disp() function prints the value I assigned so I know the function is working, but how do I access resultarray after the program has finished? I have tried declaring it as a global at the beginning of main(), which doesn't seem to do anything. My array should be passed back to main() - how do I get it to save so that I can actually use the output of my function after the program has terminated?
Thanks in advance for your help.
edit - I'm aware that the scope of main() is different, but if I get rid of it I am told that "function definitions are not permitted in this context." It looks like for some reason I can't have a script and some functions which the script uses in the same file.
If you wish to keep main as a function with this syntax, then you should edit your code as follows (return resultarray from main):
function resultarray = main()
object = matfile('data.mat')
vars = (fieldnames(object))
resultarray = zeros(length(vars))
for index = 1:length(vars)
var = vars(index)
x = object.var
resultarray = analysis(x, index)
end
end
function resultarray = analysis(x, index)
%does stuff to x
resultarray(index) = x
disp(resultarray(index))
end
The problem is that the workspace has different scope than the function you have defined.
Otherwise you can create a script called, let's say main.m:
object = matfile('data.mat')
vars = (fieldnames(object))
resultarray = zeros(length(vars))
for index = 1:length(vars)
var = vars(index)
x = object.var
resultarray = analysis(x, index)
end
and create a separate file called analysis.m, which will contain the following code:
function resultarray = analysis(x, index)
%does stuff to x
resultarray(index) = x
end

Get pointer of class object

I have an object apple created by my own class in MATLAB:
apple = classA();
The class looks like this:
classdef classA < handle
properties
color = 'red';
end
methods
function obj = classA()
% ...
end
end
end
The question: How do I get the object or handle pointer of apple? I want to search for objects by their properties, like:
isprop(eval(mat(i).name),'color')
with mat = whos. So I need to get the pointer of the object, represented by the struct mat(i).name. I just need the reference, not a copy of the desired object. The purpose is this:
If I get the pointer somehow, like
ptr_to_apple_object = get_pointer_fct( mat(i).name )
then I am able to change the properties of the apple-object like:
ptr_to_apple_object. color = 'yellow'
Do you have any ideas? Thanks.
There's really no good way to find all current objects of a particular class, but you could use whos to get a struct about all variables, loop through this and determine which ones have the property you and then modify
variables = whos;
for k = 1:numel(variables)
obj = eval(variables(k).name);
if isobject(obj) && isprop(obj, 'color')
obj.color = 'yellow';
end
end
If you're looking for a specific class, you can use the class field of the output of whos
is_class = ismember({variables.class}, 'classA');
instances = variables(is_class);
for k = 1:numel(instances)
obj = eval(instances(k).name);
obj.color = 'yellow';
end
Update
Since you are subclassing handle, when you assign your instance to a new variable (obj = val(variables(k).name) above), it does not create a copy of your instance, but rather a new reference to the same object.
b = classA;
c = b;
b.color = 'red';
c.color
% 'red'

Constructor Not Assigning Values in Matlab

I am trying to create a few objects in Matlab. I am used to programming in Java, but being able to do this in Matlab would be beneficial for my research.
So, I have a particular class:
classdef Lifter < handle
properties
weightClass = 0;
mean = 0;
var = 0;
nation = '';
end
methods
function Lifter = Lifter(weightClass,mean,var,nation) %Constructor
Lifter.weightClass = weightClass;
Lifter.mean = mean;
Lifter.var = var;
Lifter.nation = nation;
end
function set.weightClass(this,weightClass)
end
function set.mean(this,mean)
end
function set.var(this,var)
end
function set.nation(this,nation)
end
function value = get.weightClass(this)
value = this.weightClass;
end
function value = get.mean(this)
value = this.mean;
end
function var = get.var(this)
var = this.mean;
end
function nation = get.nation(this)
nation = this.nation;
end
end
end
Pretty standard, doesn't really do much.
So, in another page, I have:
function Competition()
Lifter1 = Lifter(56,1,1,'USA')
end
However, running this gives:
Lifter1 =
Lifter with properties:
weightClass: 0
mean: 0
var: 0
nation: ''
Any help to figure out why this values are not being initialized correctly from the constructor would be very helpful.
Also, an example of how to actually call a setter or getter method on my Lifter1 object would be helpful. Thank you!
Those setters are for dependent properties (declared as properties(Dependent)). But also, your setters are not implemented (empty), which means that all your property assignments won't do anything. Which means that the properties stay with the default values declared in the properties section.
Later Edit
If I would have to implement the class, I'd do it like in the following code:
classdef Lifter < handle
% --- PUBLIC SECTION ---
properties(Dependent)
weight_class;
end;
methods
function obj = Lifter(weight_class)
obj.weight_class = weight_class;
end;
function set.weight_class(obj, weight_class)
if ~isa(obj, 'Lifter') ...
|| ~isscalar(obj) ...
|| ~isvalid(obj)
error('Lifter:Arg', '"obj" must be a scalar valid handle object of class "Lifter".');
elseif ~isnumeric(weight_class) ...
|| ~isscalar(weight_class) ...
|| ~isreal(weight_class) ...
|| (weight_class <= 0) % + other value tests
error('Lifter:Arg', '"weight_class" must be a numeric positive scalar.');
else
obj.weight_class_ = double(weight_class);
end;
end;
function val = get.weight_class(obj)
val = obj.weight_class_;
end;
end;
% --- PRIVATE SECTION ---
properties(Access=private)
weight_class_;
end;
end
The code for the rest of the properties is similar. Test with:
a = Lifter(100); % Constructor + setter call
a.weight_class = 75; % Setter call
disp(a.weight_class); % Getter call
a.weight_class = '85'; % Setter call with wrong value
Your setters and getters should not contain dots (although I agree it would be more elegant your way if it worked):
function set.weightClass(this,weightClass)
end
Could be (should be) :
function set_weightClass(this,weightClass)
end
If I replace all of them, it works properly.

MATLAB - Cleanly read variables out of a function possibly using some type of varargout...?

I have function f1 which must contain subfunctions, so I can't use another script:
function vars = f1()
a = 1;
b = 'hello';
c = {[1 2 3]};
currvars = whos; %all variable info
for k = 1:size(currvars, 1)
eval(['vars.(currvars(k).name) = ' currvars(k).name ';']);
end
end
I call the function in a script, and then I create the variables in the script using genvarname() and eval():
vars = f1();
varnames = genvarname(fieldnames(vars));
for k = 1:size(varnames(:),1) %Creates vars with the struct's fieldnames.
eval([varnames{k} ' = vars.' varnames{k} ';']);
end
clearvars vars varnames
I'd like to fit the variable creation process into a function somehow while reading out all the variables only to the script calling it, but I don't want to assign a hundred different variable names to the output. Does anyone have any advice on how to do this?
DON'T CREATE zillions of automatically named variables. This is foolish and terribly poor programming style. Instead, learn to use arrays. Multidimensional arrays, cell arrays, struct arrays.
Or, do what you have done, and then be forced to find a kludge like you are looking for.
Take your pick. Eval is evil.
You could return a structure with "corrected" fieldnames:
function output = someFunc
vars = f1();
protected = { %# some list of varnames you don't want
};
names = fieldnames(vars);
newnames = genvarname(names, protected);
for k = 1:numel(newnames)
output.(newnames{k}) = vars.(names{k});
end
end
If you then use
output = someFunc;
varnames = fieldnames(output);
for k = 1:numel(fieldnames)
eval([varnames{k} ' = output.' varnames{k} ';']);
end
in the script/function where you want the variable names, you have a relatively clean way of locking everything up in the function someFunc without having to pre-define all output variable names.
You can also do this in one step:
function someFunc2
vars = f1();
protected = { %# some list of varnames you don't want
};
names = fieldnames(vars);
newnames = genvarname(names, protected);
for k = 1:numel(newnames)
assignin('caller', newnames{k}, vars.(names{k}));
end
end
Which means you just call the function
someFunc2;
in your script, and the function then defines and assigns all the variables in the script's workspace.
A tiny step forward, but forward nonetheless :)
CREDIT TO RODY...
#Old semi-"global" variables:
function vars = f1()
a = 1;
b = 'hello';
c = {[1 2 3]};
currvars = whos; %all variable info
for k = 1:size(currvars, 1)
eval(['vars.(currvars(k).name) = ' currvars(k).name ';']);
end
end
#Function to assign variables to the calling script's/function's workspace. Variable names are determined by the single structure's fieldnames:
function setvars(func)
vars = func;
protected = {'If needed, put variable names you do not want here'};
names = fieldnames(vars);
newnames = genvarname(names, protected);
for k = 1:numel(newnames)
assignin('caller', newnames{k}, vars.(names{k}));
end
end
#Script call:
setvars(f1);

MATLAB: How to create structure fields with a name defined by a string.

I have a constructor like this:
function p = class_name(folder, file_name)
xmlfile = fullfile(folder, file_name);
xDoc = xmlread(xmlfile);
struct = xml2struct(xDoc);
%lots of repetitive code
end
It reads and XML file and transforms it into a struct. The struct elements are then assign to the class's properties/fields using some repetitive code like this:
if(isfield(struct.parameters, 'parameter_name'))
p.property_name = struct.parameters.parameter_name.Text;
else
p.property_name = '';
end
I would like to put this into a method/function which, given the name of the struct element (here 'parameter_name') and the name of the class field/property (here 'property_name') assigns the former to the latter.
Is it possible to write a generic function/method for this? Thanks.
You can implement such a function using dynamic field names. This is the recommended implementation for such cases:
function p = setparam(s, p, param_name, prop_name)
if(isfield(s.parameters, param_name))
param = s.parameters.(param_name);
p.(prop_name) = param.Text;
else
p.(prop_name) = '';
end
end
You can also use setfield and getfield on older versions of MATLAB:
function p = setparam(s, p, param_name, prop_name)
if(isfield(s.parameters, param_name))
param = getfield(s.parameters, param_name);
p = setfield(p, prop_name, getfield(param, 'Text'));
else
p = setfield(p, prop_name, '');
end
end
Do not use struct for structure name in your code - it is a reserved keyword.
Use dynamic field names:
yourStruct.parameters.('parameter_name')
Here is a a generic function:
Can be used for either structs or class objects
function obj_to = set_props(obj_to, obj_from)
% insert properties from obj_from into obj_to.
props_from = fieldnames(obj_from);
props_to = fieldnames(obj_to);
for k = 1 : length(props_to)
if ismember(props_to{k}, props_from)
obj_to.(props_to{k}) = obj_from.(props_to{k});
else
obj_to.(props_to{k}) = '';
end
end
Now, in the constructor:
function obj = class_name(folder, file_name)
xmlfile = fullfile(folder, file_name);
xDoc = xmlread(xmlfile);
s = xml2struct(xDoc); % do not use word "struct" for variables
set_props(obj, s); % if obj has handle, no need to return it from set_props()
end