Matlab - Manipulating datasets within subclass methods - matlab

I am having some difficulty designing a subclass of dataset in Matlab (R2010b). I am experienced programming Matlab, but new to using its OOP features. My constructor seems to be fine, but when I try to build some methods that access data in the dataset, I can't seem to get it to work. Here is an example:
classdef mydataset < dataset
properties
end
methods
function [obj] = mydataset(obs,array)
% obs is N x 1 cell array of strings
% array is N x 2 double array
obj = obj#dataset({array,'Field1','Field2'},'ObsNames',obs)
end
function [val] = computeValue(obj)
col = obj.Field1;
% I get an error above regardless of how I try to access the dataset.
% e.g. col = double(obj(obs,'Field1')) also does not work.
% Some more code using col to determine val
end
end
end
In my method computeValue, I am trying to access the data in the dataset using dataset syntax, i.e. on the command line I could access Field1 using ".". It complains there is no method, property, or field Field1 for class mydataset. If I try the alternate syntax
col = double(obj(:,'Field1'));
it complains about the size of obj, e.g. "Index exceeds matrix dimensions".
I found a workaround using subsref:
methods
function [val] = computeValue(obj)
s.type = '.';
s.subs = 'Field1';
col = subsref(obj,s);
% Some more code using col to determine val
end
end
Although the workaround works, it is not very convenient and largely defeats the purpose of wanting a subclass of dataset. Is there some attribute or something simple I am missing?
Thank you very much.
Eric

Can you post the complete code of your class. I suppose you didn't declare your property "factor" and try to access it.
Your class should look like this :
classdef MyClass
properties
factor;
end
methods
function obj = MyClass(factor)
% The constructor set the property factor
obj.factor = factor;
end
function val = computeValue(obj)
col = obj.factor;
% ...
end
end
end

Related

Matlab class dynamic filling of a property

I'm trying to dynamically fill a property in a Matlab class.
I pass vectors to a method function and then compute various parameters. I would like to fill the properties in a for loop, see code example. The OwnClassFunction is just an example of a further function in the class, but is not implemented in the code example. How can I do this correctly?
classdef Sicherung < handle
properties
x = ([],1)
end
methods
function examplefunction(object,...
single_parameter_vector) % (n,1) n can be any size
for i=1:length(param_vector)
[object.x(i,1)] = object.OwnClassFunction(single_parameter_vector(i,1));
end
end
end
end
If i try something like that
...
properties
x = []
end
...
function ...(object,parameter)
for i=1:length(parameter)
[object.x(i)] = function(parameter(i));
end
I get the error message Subscripted assignment dimension mismatch.
I don’t have MATLAB in hand to test, but the following should work.
Your code is pretty close to a correctly functioning method. Change it as follows:
classdef Sicherung < handle
properties
x = [] % initialize to empty array
end
methods
function examplefunction(object,param_vector)
if ~isvector(param_vector)
error('vector expected') % check input
end
n = numel(param_vector)
object.x = zeros(n,1); % preallocate
for i=1:n
object.x(i) = object.OwnClassFunction(param_vector(i));
end
end
end
end

Array of objects in generable matlab function

In simulink model I have a matlab function block. Inside the function I would like to create an array of objects in a way it is compatible with code generation.
My question is similar to the one answered here: Construct an array of objects in MATLAB
The problem is "compatible with code generation" part.
When I try to do it with repmatmatlab returns:
Arrays of objects are not supported for code generation.
When I try to do it with array of objects I see:
Recursive calls are not allowed. Function 'dummyClass.dummyClass'
participated in a recursive call.
Please find below the code I run:
embedded matlab function
function y = fcn(u)
%#codegen
x = [1 2 3];
% %% repmat way
% aa = dummyClass(x(1));
% aaArray = repmat(aa,1,3);
%% array of objects
aa = dummyClass(x);
y = u;
class file
classdef dummyClass
properties
value
end
methods
function obj = dummyClass(value)
%% array of objects
if nargin~=0
m = size(value,1);
n = size(value,2);
obj(m,n) = dummyClass;
for i = 1:m
for j = 1:n
obj(a,b).value = value(a,b);
end
end
end
% %% repmat
% obj.value = value;
end
end
end
Uncomment
As of MATLAB R2017a, there's no way to create arrays of objects that is compatible with code generation using MATLAB Coder or Simulink Coder.
As the first error message says, "arrays of objects are not supported for code generation" - it's not a problem with any specific way you're attempting to create them, they're just not supported at all.
MathWorks may introduce this feature in a future version, but it's not there right now.

Efficient way of passing data between MATLAB functions

I am solving a very large optimization problem. The objective function and constraint function needs numerous data. Currently I am passing the data as a structure to them.
myFS(X, Dat, g_Index, f_Index) % Dat is a structure which includes many variables
Do you think it's an efficient way to reduce the elapsed time?
What better alternatives do exist?
Is this what the given answer, regarding to class definition, means?
%% First we define the class in a separate file:
classdef myDataStructure < handle
properties
NRES;
NOBJ;
NVAR;
end
methods
function obj = myDataStructure()
end
end
end
%% In another file where the main program is, we initialize the class.
Dat = myDataStructure();
%% Initialize
Dat.NRES = 1;
Dat.NOBJ = 1;
Dat.NVAR = 1;
[myF, Dat_updated] = BBB(Dat);
%% Here we define the function and use the class
function [f, CalssDat] = BBB(CalssDat)
x = CalssDat.NRES;
y = CalssDat.NOBJ;
z = CalssDat.NVAR;
f = x + y + z;
CalssDat.NOBJ = 2;
end
As far as I know, MATLAB does not actually copy the content of the data you pass to a function until the point when you modify it in the function itself - in which case it makes a local copy and that takes some CPU time.
Therefore, as long as Dat doesn't change inside myFS(), what you are doing now does not add any CPU overhead. In case you do change the values of Dat inside myFS() and want to return it, I can think of two ways to optimise it:
You can declare myFS() as: function [Dat, anythingElse] = myFs(X,Dat,g_Index, f_Index), which should prevent matlab from making a local copy.
Another approach is to use a class that derives from handle and have Dat be a member of that. This way, whenever you pass the object containing Dat, you only pass the object handle and not a copy of the object itself.
Example of the second approach:
classdef myDataStructure < handle
properties
p1FromDat;
p2FromDat;
% .
% .
% .
pNFromDat;
end
methods
function obj = myDataStructure()
% Add initialization code here if you want. Otherwise p1FromDat
% ... pNFromDat are accessible from outside
end
end
end
Than, in your code:
Dat = myDataStructure();
Dat.p1FromDat = 1;
Dat.p2FromDat = 1;
And in your myFs() you use Dat exactly the same way as you used before.
Because myDataStructure derives from handle, the data inside will not be copied when you pass Dat around.
Do be careful with this, because when you change Dat in myFS(), the values will be changed outside the scope of myFS() as well.

creating rational class constructor in matlab

suppose we have following class,i want to declare rational number class in matlab,i am beginner of object oriented programming in matlab languages and i want to learn basics
classdef ratnum %rational number class
properties (Access=protected)
n %numerator
d %denomerator
end
methods
function r=ratnum(numerator,denomenator)
r.n=numerator;
r.d=denomenator;
end
end
end
how can i create constructor with specific values in matlab main part?should i use name of class ?thanks in advance
To instantiate an object of this class you can use: num1 = ratnum(2,3)
Since MATLAB doesn't have method overloading that is based on the amount of passed inputs, you could use nargin to select the correct scenario, as follows:
classdef ratnum %rational number class
properties (Access=protected)
n %//numerator
d %//denominator
end
methods
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%//whatever you want the defaults to be
end
end
end
end
A simple debug trick is to do num1_str=struct(num1) which allows you to see the contents of the object. However, you should create some public methods to get the values (instead of turning the object to a struct every time).
To overload the default summation of MATLAB you need to understand that whenever you write a+b it is automatically translated into plus(a,b). When defining custom classes with custom summation you should make a folder that has the name #classname (in your case #ratnum) and in it:
ratnum.m: the class definition file (which is the code you wrote)
a file named plus.m which looks something like:
.
function sum = plus(ratnum1,ratnum2)
ratnum1 = ratnum(ratnum1);
ratnum2 = ratnum(ratnum2);
sum = (...
ratnum1.r*ratnum2.d + ...
ratnum2.r*ratnum1.d )/ ...
(ratnum1.d * ratnum2.d);
end
Then, when you use + to add ratnums it will use the correct plus function.
Here's some helpful reading: MATLAB Documntation: Implementing Operators for Your Class
To call class methods, even from within other class methods, you must always write the class name first: ratnum.sum(ratnum1). Here's an example:
classdef ratnum %rational number class
properties (Access=public)
n %//numerator
d %//denominator
end
methods (Access = public)
function r = ratnum(numerator,denominator)
switch nargin
case 2
r.n=numerator;
r.d=denominator;
case 0
%whatever you want the defaults to be
end
end
end
methods (Access = public, Static)
function out = sum(ratnum)
out = ratnum.n + ratnum.d;
end
end
end
then:
>> a = ratnum(1,1)
a =
ratnum with properties:
n: 1
d: 1
>> ratnum.sum(a)
ans =
2
If you want to overload constructor with many different forms you'll have to initialize missing parameters with default value (or use varargin for more complex overloads):
function [r] = ratnum(num, den, varargin)
% Showing initializing missing parameters
if (nargin < 2), den = 42; end
if (nargin < 1), num = 7; end
% Showing working with varargin
if (nargin == 3)
...
elseif((nargin > 1) && (ischar(varargin{1}))
...
else
...
end
end
If you want to create named initializers for clarification of their meaning, you'll have to do it with Static methods:
methods (Static)
function [r] = TwoThird()
r = ratnum(2, 3);
end
function [r] = Half()
r = ratnum(1, 2);
end
end
Which can be used like this:
dummy = ratnum.Half(); % Ratio is 1/2
dummy = ratnum.TwoThird(); % Ratio is 2/3
dummy = ratnum(42, 666); % Ratio can be any custom one

Matlab - how to create a subclass of dataset class keeping the dataset parameter constructor

dataset allows us to do:
x = rand(10, 1);
y = rand(10, 1);
d = dataset(x, y);
d will have 2 variables with name 'x' and 'y' and content x and y - variable names are obtained from the workspace. The dataset() call above is equivalent to:
d = dataset({'x', x}, {'y', y});
when the names are specified.
Now if I have a subclass of dataset:
classdef mydataset < dataset
properties
end
methods
function spec = mydataset(varargin)
spec = spec#dataset(varargin{:});
% Add some more things to this subclass because that's the reason I need a subclass
end
end
end
The problem is, if I call:
d = mydataset(x);
d will have the variable x but the name is just 'var1'. The workspace name 'x' is not recognized. Unless I call:
d = mydataset({'x', x});
I will not get the same effect.
Any solution?
Note that I do not want to lose other argument parsing abilities of dataset(). It can process really complicated arguments, and I do want to preserve that.
http://www.mathworks.com/help/toolbox/stats/dataset.html
A = dataset(varspec,'ParamName',Value)
A = dataset('File',filename,'ParamName',Value)
A = dataset('XLSFile',filename,'ParamName',Value)
A = dataset('XPTFile',xptfilename,'ParamName',Value)
The example in this question with mydataset(x) is the a simple and commonly encountered situation that mydataset() can't pass things to dataset() and obtain the same results. Thus it's an important situation. But to do just that and lose other capabilities of dataset() is not worth it.
One option is to capture the argument names yourself and build a cell that you then pass in to the dataset constructor, i.e. you build a cell that looks like
{{Var1 VarName1}, {Var2 VarName2}, ...}
A quick and dirty solution:
classdef mydataset < dataset
properties
end
methods
function self = mydataset(varargin)
for k = 1:nargin
args{k} = {varargin{k}, inputname(k)};
end
self = self#dataset(args{:});
end
end
end
Now if I call it:
>> x=1;
>> y=2;
>> mydataset(x,y)
ans =
x y
1 2
Of course, you've now lost the ability to call mydataset with the {val, valname},... syntax, but maybe that's worth giving up. If you also wanted to be able to do that, you would need to write a conditional that checks the format of your input first, and builds args differently depending on the input format.
Note that you can't do the obvious thing and put your calls to the superclass constructor inside two branches of an if statement. In Matlab, calls to the superclass have to be at the top level (i.e. you can't put them inside loops or conditionals).