Extract a value from MATLAB codistributed array - matlab

I am attempting to build a distributed array of handle class objects in MATLAB and I would like to extract a specific handle from this vector for use on the command line. Given the code below, I would like the following to execute. I am running this on with two labs (matlabpool 2). The getValue function is what I need assistance with, thanks...
vec = buildArray;
h = getValue(vec,6);
h.id
ClassA.m:
A class that I would like to distribute in parallel.
classdef ClassA < handle
properties
id;
end
methods
function obj = ClassA(id)
obj.id = id;
end
end
end
buildArray.m:
A function to build codistributed array from local instances of ClassA.
function vec = buildArray
X(:,1) = 1:10; % create ids
gsize = size(X); % the global size
X = distributed(X); % distribute the ids
spmd
x = getLocalPart(X); % extract the local ids
local = cell(length(x),1); % create local storage for handles
% Create the class instances
for i = 1:length(x);
local{i} = ClassA(x(i));
end
% Build the codistributed array of handles
codist = codistributor1d(codistributor1d.unsetDimension, ...
codistributor1d.unsetPartition, gsize);
vec = codistributed.build(local,codist);
end
getValue.m:
This is the function that I need help with, currently it just displays what lab that contains the class with the specified id. I would like for it to return the handle so it may be used from the command line. How is this done?
function h = getValue(vec, id)
h = []; % just so it will not throw an error
spmd
local = getLocalPart(vec);
for i = 1:length(local);
if local{i}.id == id;
% Export h here
disp(['ID ', num2str(id), ' is on lab ', num2str(labindex)]);
break;
end
end
end

I was able to get my problem working using this for getValue.m, is there a better way?
function h = getValue(vec, id)
spmd
local = getLocalPart(vec);
idx = [];
for i = 1:length(local);
if local{i}.id == id;
idx = i;
break;
end
end
codist = codistributor1d(codistributor1d.unsetDimension, ...
codistributor1d.unsetPartition, [numlabs,1]);
IDX = codistributed.build(idx, codist);
end
c = gather(vec(IDX));
h = c{1};

Related

How to save persistent variable into .mat file?

I have a model of device which have internal state between calls.
Previously I passed that state in function call and returned a new state when exited from function.
Then, I found out about persistent variables which was exactly what I need. But problem is when I need to debug model or design between multiple calls it's hard to reproduce the exact call that I need.
For example, I have function foo:
function [y] = foo(x)
persistent k;
if isempty(k)
k = 0;
end
y = k*x;
k = k+1; %% or even k = rand
end
I have multiple runs:
x = 1:5;
for i = 1:5
y = foo(x(i))
end
and have an error in 4'th call. Currently I need to run first three calls to get function state that actual for 4'th call (and if k was equal rand, I will not be able reach that state at all).
I tried to save workspace between calls to have an option to load all states but that doesn't work:
for i = 1:3
y = foo(x(i))
end
save foo3.mat
for i = 4:5
y = foo(x(i))
end
clear all
load foo3.mat
foo(3)
ans =
0
So how can I save that function state?
Actually, I can save that variable while function is run by putting save statement in code of function but for me that's seems not right. I think that statement should be at the top-script.
I suppose the most appropriate solution to my question is replace persistent variable by global one. In that case I have minimum changes to original code:
function [y] = foo(x)
global k;
if isempty(k)
k = 0;
end
y = k*x;
k = k+1; %% or even k = rand
end
And debugging like:
x = 1:5;
for i = 1:3
y = foo(x(i))
end
global k;
save("foo3.mat","k")
clear all
load foo3.mat
foo(4)
The best solution I found is to create class-based model and move variables that stores state into class property. I can save class-object like any other variable so I can save any intermediate state of model:
classdef foo < handle
properties(Access = private)
k;
end
methods
function self = foo()
self.k = 0;
end
function [y] = bar(self, x)
y = self.k*x;
self.k = self.k+1; %% or even k = rand
end
end
end
And debug like:
f = foo();
x = 1:5;
for i = 1:3
y = f.bar(x(i))
end
save bar3.mat
for i = 4:5
y = f.bar(x(i))
end
clear f
load bar3.mat
f.bar(4)
In that case I don't need to pass and return states and I can load any inermediate state.
A couple of options:
clear
Dont use 'clear all'. You rarely if ever need to do clear all, a simple clear is usually sufficient.
mlock
Put mlock in your function, note this has other implications which you should understand by looking at the documentation. Primarily you have to unlock (munlock) it to edit the function file.
Note this will keep your persistent variable for the matlab session only.
function [y] = foo(x)
persistent k;
mlock;
if isempty(k)
k = 0;
end
y = k*x;
k = k+1; %% or even k = rand
end

Custom learner function for Adaboost

I am using Adaboost to fit a classification problem. We can do the following:
ens = fitensemble(X, Y, 'AdaBoostM1', 100, 'Tree')
Now 'Tree' is the learner and we can change this to 'Discriminant' or 'KNN'. Each learner uses a certain Template Object Creation Function. More info here.
Is it possible to create your own function and use it as a learner? And how?
I open templateTree.m and templateKNN.m to see how MATLAB define Template Object Creation Function.
function temp = templateKNN(varargin)
classreg.learning.FitTemplate.catchType(varargin{:});
temp = classreg.learning.FitTemplate.make('KNN','type','classification',varargin{:});
end
and
function temp = templateTree(varargin)
temp = classreg.learning.FitTemplate.make('Tree',varargin{:});
end
It shows that MATLAB has a function in FitTemplate named make , if you open this m-file, you will see :
function temp = make(method,varargin)
% Check the type of the required argument
if ~ischar(method)
error(message('stats:classreg:learning:FitTemplate:make:BadArgs'));
end
% Extract type (classification or regression)
args = {'type'};
defs = { ''};
[usertype,~,modelArgs] = ...
internal.stats.parseArgs(args,defs,varargin{:});
% Check usertype
if ~isempty(usertype)
usertype = gettype(usertype);
end
% Method
namesclass = classreg.learning.classificationModels();
namesreg = classreg.learning.regressionModels();
[tfclass,locclass] = ismember(lower(method),lower(namesclass));
[tfreg,locreg] = ismember(lower(method),lower(namesreg));
if ~tfclass && ~tfreg
error(message('stats:classreg:learning:FitTemplate:make:UnknownMethod', method));
end
if tfclass && tfreg
method = namesclass{locclass}; % can get it from namesreg too
type = usertype;
% If type is not passed for an ensemble method, try to
% figure it out from learner types. This is useful for
% users who want to type
% fitensemble(X,Y,'Subspace',100,'Discriminant')
% instead of
% fitensemble(X,Y,'Subspace',100,'Discriminant','type','classification')
if isempty(type) && ismember(method,classreg.learning.ensembleModels())
[learners,~,~] = internal.stats.parseArgs({'learners'},{},modelArgs{:});
if ischar(learners) || isa(learners,'classreg.learning.FitTemplate')
learners = {learners};
elseif ~iscell(learners)
error(message('stats:classreg:learning:FitTemplate:make:BadLearnerTemplates'));
end
L = numel(learners);
% The user can pass several learner templates, and some
% of these learners may be appropriate for
% classification, some for regression, and some for
% both. The ensemble type cannot be determined
% unambiguously unless if all learners are appropriate
% for one type of learning *only*. For example, in 12a
% t1 = ClassificationDiscriminant.template
% t2 = ClassificationKNN.template
% fitensemble(X,Y,'Subspace',10,{t1 t2})
% is going to work because both discriminant and k-NN
% can be used for classification only. If you want to
% mix discriminant and tree, you have to specify the
% ensemble type explicitly:
% t1 = ClassificationDiscriminant.template
% t2 = ClassificationTree.template
% fitensemble(X,Y,'Bag',10,{t1 t2},'type','classification')
types = zeros(L,1); % -1 for regression and 1 for classification
for l=1:L
meth = learners{l};
if isa(meth,'classreg.learning.FitTemplate')
meth = meth.Method;
end
isc = ismember(lower(meth),lower(namesclass));
isr = ismember(lower(meth),lower(namesreg));
if ~isc && ~isr
error(message('stats:classreg:learning:FitTemplate:make:UnknownMethod', meth));
end
types(l) = isc - isr;
end
if all(types==1)
type = 'classification';
elseif all(types==-1)
type = 'regression';
end
end
elseif tfclass
method = namesclass{locclass};
type = 'classification';
else
method = namesreg{locreg};
type = 'regression';
end
% Make sure the type is consistent
if ~isempty(usertype) && ~strcmp(usertype,type)
error(message('stats:classreg:learning:FitTemplate:make:UserTypeMismatch', method, usertype));
end
% Make template
temp = classreg.learning.FitTemplate(method,modelArgs);
temp = fillIfNeeded(temp,type);
end
You must change this function.

vectorization in matlab class

I have a class in MATLAB that represents an imaginary number. I have a constructor and two data members: real and imag. I am playing with overloading operator in a class and I want to make it work with matrices:
function obj = plus(o1, o2)
if (any(size(o1) ~= size(o2)))
error('dimensions must match');
end
[n,m] = size(o1);
obj(n,m) = mycomplex();
for i=1:n
for j=1:m
obj(i,j).real = o1(i,j).real + o2(i,j).real;
obj(i,j).imag = o1(i,j).imag + o2(i,j).imag;
end
end
end
But I don't want to use for loops. I want to do something like:
[obj.real] = [o1.real] + [o2.real]
But I don't understand why it does not work... the error says:
"Error in + Too many output arguments".
I know that in MATLAB it is good to avoid for loops for speed up... Can someone explain me why this does not work, and the right way to think about vectorization in MATLAB with an example for my function?
Thanks in advance.
EDIT: definition of my complex class:
classdef mycomplex < handle & matlab.mixin.CustomDisplay
properties (Access = public)
real;
imag;
end
methods (Access = public)
function this = mycomplex(varargin)
switch (nargin)
case 0
this.real = 0;
this.imag = 0;
case 1
this.real = varargin{1};
this.imag = 0;
case 2
this.real = varargin{1};
this.imag = varargin{2};
otherwise
error('Can''t have more than two arguments');
end
obj = this;
end
end
end
Consider the implementation below. First some notes:
the constructor can be called with no parameters. This is important to allow preallocating object arrays: obj(m,n) = MyComplex()
for convenience, the constructor accepts either scalar of array arguments. So we can call: c_scalar = MyComplex(1,1) or c_array = MyComplex(rand(3,1), rand(3,1))
the plus operator uses a for-loop for now (we will later change this).
(Note that I skipped some validations in the code, like checking that o1 and o2 are of the same size, similarly for a and b in the constructor).
classdef MyComplex < handle
properties
real
imag
end
methods
function obj = MyComplex(a,b)
% default values
if nargin < 2, b = 0; end
if nargin < 1, a = 0; end
% accepts scalar/array inputs
if isscalar(a) && isscalar(b)
obj.real = a;
obj.imag = b;
else
[m,n] = size(a);
obj(m,n) = MyComplex();
for i=1:m*n
obj(i).real = a(i);
obj(i).imag = b(i);
end
end
end
function obj = plus(o1, o2)
[m,n] = size(o1);
obj(m,n) = MyComplex(); % preallocate object array
for i=1:m*n % linear indexing
obj(i).real = o1(i).real + o2(i).real;
obj(i).imag = o1(i).imag + o2(i).imag;
end
end
end
end
An example of using the class:
% scalar objects
>> c1 = MyComplex(1,2);
>> c2 = MyComplex(3,4);
>> c3 = c1 + c2
c3 =
MyComplex with properties:
real: 4
imag: 6
% array of objects
>> c4 = [c1;c1] + [c2;c2]
c4 =
2x1 MyComplex array with properties:
real
imag
Now here is a vectorized version of the plus method:
function obj = plus(o1, o2)
[m,n] = size(o1);
obj(m,n) = MyComplex();
x = num2cell([o1.real] + [o2.real]);
[obj.real] = deal(x{:});
x = num2cell([o1.imag] + [o2.imag]);
[obj.imag] = deal(x{:});
end
I'm using the syntax: [objarray.propName] to reference a property in object arrays, this return the values as a vector.
For the opposite of assigning a property in an object array, I use comma-separated lists, thus I had to convert to a cell array to get the x{:} convenient syntax.
Note that the deal call is not strictly needed, we could write the assignment without it:
[obj.real] = x{:};
The line obj(n,m) = mycomplex() looks very suspicious. I think what you want to do there is obj = mycomplex(n,m) instead.
I can't see the rest of your code, but it's miraculous to me that this line even works. I suspect that you have an obj variable stored somewhere already, and this code simply overwrites one entry of that variable. I predict that if you clear all variables, it's going to fail on that line.
Again, it's very difficult to understand what happens without knowing what mycomplex() actually does.

Assign value to cell array through function MATLAB

I'm attempting to make a crude implementation of the AP CS 'gridworld' using matlab, albiet with fewer classes. So far I have a superclass 'Location' with the properties row and col. Next I have 'Grid' with just a cell array called grid. Using the Grid.get command, I can retrieve objects from that cell array. The problem though, is that I cannot get the Grid.put function to work. Testing without using the function allows me to put test strings into testGrid.grid{}, but the function doesn't seem to work.
classdef Location
properties
row;
col;
end
methods
%constructor, intializes with rows/columns
function loc = Location(r,c)
if nargin > 0
loc.row = r;
loc.col = c;
end
end
function r = getRow(loc)
r = loc.row;
end
function c = getCol(loc)
c = loc.col;
end
function display(loc)
disp('row: ')
disp(loc.row)
disp('col: ')
disp(loc.col)
end
end
Grid class, child of location:
classdef Grid < Location
properties
grid;
end
methods
function gr = Grid(rows, cols)
if nargin > 0
gr.grid = cell(rows,cols);
end
end
function nrows = getNumRows(gr)
[nrows,ncols] = size(gr.grid);
end
function ncols = getNumCols(gr)
[nrows,ncols] = size(gr.grid);
end
function put(gr,act,loc)
gr.grid{loc.getRow,loc.getCol} = act;
end
function act = get(gr,loc)
act = gr.grid{loc.getRow(),loc.getCol()};
end
end
Finally, the test commands from the command window
testLoc = Location(1,2)
row:
1
col:
2
testGrid = Grid(3,4)
row:
col:
testGrid.put('testStr',testLoc)
testGrid.get(testLoc)
ans =
[]
testGrid.grid{1,2} = 'newTest'
row:
col:
testGrid.get(testLoc)
ans =
newTest
Thanks for any insight!
You need to return the object from your functions and use that as your new object. So
function put(gr,act,loc)
gr.grid{loc.getRow,loc.getCol} = act;
end
Should be
function gr = put(gr,act,loc)
gr.grid{loc.getRow,loc.getCol} = act;
end
And then you can use it like
testGrid = Grid(3,4)
testGrid = testGrid.put(act, loc)
testGrid.get(loc)
And you can also chain the calls
testGrid.put(act, loc).get(loc)

plotting two functions on the same trendline in matlab

This is my original code:
function a = graph_times()
merge_times = [];
for i = 100:100:1000
curr = sort_timer(i);
merge_times = [merge_times, curr(1)];
end
plot(100:100:1000, merge_times);
a = 1;
end
I want to modify this code so that it plots trendlines for both insertion_sort and merge_sort on the same graph.
Below are the functions for merge_sort and insertion_sort
function c = insertion_sort(list1)
inserted = [];
for i = 1:size(list1,2)
inserted = insert_in_order(inserted,list1(1,i))
c = inserted
end
steps2=0;
function b = merge_sort(nums)
if size(nums,2) == 1
b = nums;
return;
end
You can give several sets of coordinates to MATLAB's plot function. You can plot the times of the two sorting algorithms like so:
plot(100:100:1000, merge_times, 100:100:1000, insertion_times);