I have created the following class, which inherits both from handle and enum.
classdef ShiftType < handle
%SHIFTTYPE Defines shift per frame
properties
shift = 0
num_shifts = 0
end
enumeration
LateralCst %in meters
RadialCst % in radians
RadialVar % in beam distance ratio
LateralVar % Same. Lateral shift calculated at focus range.
end
end
If I create an instance of ShiftType and use it within a script, everything goes well. But I realized that, if I save this instance into a .mat file and then load it, its properies are set to their default value (0). Here is an example to illustrate the problem:
>> shift_type = ShiftType.RadialVar;
>> shift_type.shift = 0.5;
>> shift_type.num_shifts = 4;
>> shift_type
shift_type =
RadialVar
>> shift_type.shift
ans =
0.5000
>> save test.mat shift_type
>> clear all
>> load test.mat
>> shift_type
shift_type =
RadialVar
>> shift_type.shift
ans =
0
How can I have the properties saved in the .mat files along with the ShiftType instance?
Note that those properties are independant of the Enum type, so I don't want to just have a ShiftType(val) function and default values for each enum (such as LateralCst (1, 4)).
Thanks ahead!
It is most probably a bug. The documentation says that the property set methods should be called when the object is loaded however if you add this method to your class:
function set.shift(obj, shift)
obj.shift = shift;
disp('Set method called!');
end
You'll see that it is not being called. If you remove the enumeration part of the class, it works fine. Appears that loading of enumeration types have their own specific handling which doesn't take care of other properties.
Thanks for your answers. I have reported the bug to Matlab.
In the meantime I have fixed the issue by dividing ShiftType into two classes. The class Shift is a generic class with editable properties, one of which is an instance of the enum type of before (ShiftType).
classdef Shift
%SHIFT Defines shift per frame
properties
type = ShiftType.RadialVar;
val = 0; % Ref ShiftType
num_shifts = 0;
end
methods
function obj = Shift(type, val, num_shift)
obj.type = type;
obj.val = val;
obj.num_shifts = num_shift;
end
end
end
And:
classdef ShiftType
%SHIFTTYPE Defines shift type
enumeration
LateralCst %in meters
RadialCst % in radians
RadialVar % in beam distance ratio(1 = moves from one beam to another).
LateralVar % Same. Lateral shift calculated at focus range.
end
end
I think it is the most straightforward approach until the bug is fixed.
Thanks again for your answers :)
Here is something I wrote. I won't say its perfect. But gets the job done for now. There is no change required in the class file (Same class file). Just run this code
%% Initialise data
shift_type = ShiftType.RadialVar;
shift_type.shift = 0.5;
shift_type.num_shifts = 4;
%% save file
file_name='test11.mat'; % write filename
class_object='shift_type';
class_name=class(eval(class_object));
propNames=properties(class_name);
data=cell(1,size(propNames,1)+1);
data{1}=class_object;
for index=2:size(propNames,1)+1
propertyName=strcat(class_object,'.',propNames{index-1});
data{index}=[propNames(index-1) eval(propertyName)];
end
save(file_name,class_object,'data');
%% clear workspace
clear all;
%% load file
file_name='test11.mat'; %read filename
load(file_name);
for index=2:size(data,2)
property=data{index};
propertyName=strcat(data{1},'.',property{1});
expresn=strcat(propertyName,'=',num2str(property{2}),';');
eval(expresn);
end
%% Display data
shift_type.shift
shift_type.num_shifts
Related
In R2018b, consider the following toy class:
classdef MyObj < handle
properties
use_parallel = true
test_value = NaN
end
methods
function myMethod(obj)
% Call one of the nested functions below:
if all([obj.use_parallel])
parallel();
disp('Parallel (inside myMethod):')
[obj.test_value]
else
sequential();
disp('Sequential (inside myMethod):')
[obj.test_value]
end
% Sequentially assign some values
function sequential()
for ii = 1:numel(obj)
obj(ii).test_value = ii; end
end
% Assign some values in parallel
function parallel()
parfor ii = 1:numel(obj)
set_value(obj(ii),labindex());
obj_copy(ii) = obj(ii);
end
obj = obj_copy;
end
end
end
end
% parfor requires subfunction (and not nested function):
function set_value(obj,index)
obj.test_value = index;
end
Though this question closely resembles this and this question, their underlying problem was essentially some variant of the limitation outlined in the documentation:
You can send handle objects as inputs to the body of a parfor-loop. However, any changes made to handle objects on the workers during loop iterations are not automatically propagated back to the client. That is, changes made inside the loop are not automatically reflected after the loop
However, as far as I can see, the toy class above is compliant with the parfor slicing rules as well as these particulars regarding handle classes. In my understanding, it should therefore correctly copy the modified obj back to myMethod's workspace.
However, running the following:
clc
% Assign sequentially
M(3) = MyObj();
[M.use_parallel] = deal(false);
M.myMethod();
disp('Sequential (outside class):')
[M.test_value]
disp(' ')
% Assign in parallel
N(3) = MyObj();
[N.use_parallel] = deal(true);
N.myMethod();
disp('Parallel (outside class):')
[N.test_value]
gives on my parpool of 6 workers:
Sequential (inside myMethod):
ans =
1 2 3 % <- OK
Sequential (outside class):
ans =
1 2 3 % <- OK. Nothing unexpected
Parallel (inside myMethod):
ans =
1 1 1 % <- OK, apparently, lab 1 did everything
Parallel (outside class):
ans =
NaN NaN NaN % <- hmmm...changes did not propagate
This means the obj.test_value gets correctly assigned, and the modified obj is indeed correctly copied into myMethod's workspace. Yet somehow, this modified obj is a different entity than the obj before modification, because the changes do not propagate higher up the stack...
Changing the parallel() function to a subfunction (instead of a nested function) and explicitly passing the obj parameter around, does not affect this outcome.
Sooooo...what's going on here?
I can reduce the problem to this:
classdef MyObj < matlab.mixin.Copyable
properties
test_value = NaN
end
methods
function myMethod(obj)
obj = obj.copy();
obj.test_value = rand;
disp('Inside method:')
obj.test_value
end
end
end
Removing nested functions, subfunctions and parfor from the equation. Running the code (after obvious changes) above results in:
Inside method:
ans =
4.8089e-01 % <- obj re-initialized OK
Outside class:
ans =
NaN % <- but this does NOT modify the handle class!
That means it's a language "feature" I wasn't aware of! Apparently, methods can modify existing objects, but not redefine them completely. I'll try digging in the documentation to find out some more about this, but this poses a whole new problem: how to copy the changes made by parfor back into the object?
TL;DR:
function myMethod(obj)
% ↓ new object ↓ old object
obj = obj.copy();
Cris was right; though the new and old objects have identical names, they are different things—they shadow each other. Any changes made to the new obj will not modify the old obj.
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.
A = B(1, :)
.. copies the first row of B to A.
Is there anyway to create a matrix view object, something like
frB = view(B(1, :))
to be able to refere to a view of a matrix ? Also, this would make it so
B(1, 3) = 123123; % set B(1, 3) to 123123 for illustration purposes
frB(3) = 9999; % set B(1, 3) to 9999
disp(B(1, 3)); % prints 9999
See this NumPy example which does exactly that:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.view.html
You can use pointers in Matlab to point to the same matrix without making a copy. Here's a simple example based on code from Using pointers in Matlab
First you define a class that inherits from the handle class, which is Matlab's pointer class. The class properties will store your matrix.
classdef HandleObject < handle
properties
Object=[]; % This will be your matrix
end
methods
function obj=HandleObject(receivedObject) %This is the constructor
obj.Object=receivedObject;
end
end
end
To declare your matrix and your matrix view, you do the following
M = HandleObject(ones(5,5)); %The constructor passes the matrix to the Object property
M_view = M; %M_view is a copy of the pointer
M.Object(1,1) = 5; %Change the matrix by changing the Object property
display(M_view.Object(1,1)) %This should display 5
You could add more functions to the HandleObject to correspond to your desired views.
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
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