I have a class with a scheduler function that is supposed to insert characters into a cell array:
classdef timeline < handle
properties
schedule
i
%other properties
end
methods
%other functions
function t = timeline()
%other initializations
t.schedule = cell(1,738);
t.i = 1;
end
function scheduler(t, g, fT)
if nargin == 2
fT = t.i;
end
if strcmp(g,'science')
'science' % eclipse occurs after
for j = (fT+t.sTime+1) : (fT+t.sTime+1+t.eTime)
t.schedule{j} = 'e';
end
elseif strcmp(g,'pass')
'pass' % science occurs 2 hrs after end
for j = (fT) : (fT+t.pTime)
t.schedule{j} = 'p'
end
for j = (fT+t.pTime+121) : (fT+t.pTime+120+t.sTime)
t.schedule{j} = 's';
end
scheduler(t, 'science', fT+t.pTime+120);
end
end
end
end
In the command window, I define my object t = timeline() and a mode g = 'pass' and then call the scheduler, t.scheduler(t,g).
It doesn't change the schedule property. What's going on inside the if statements to write the schedule isn't the problem I am concerned with. I put outputs in each part of the if statement, and found that strcmp is returning false and skipping over the whole block. So, I added a break point in the scheduler function, and found that for some reason g is passed to the function as another timeline object instead of the string 'pass'. Why is this?
When you call a method for an object you can use dot notation or function notation. Dot notation means you call the method using the dot operator on the object instance. For example,
obj.methodName(args);
In function notation you pass the object instance variable as the first argument to the method. For example,
methodName(obj, args);
Both the above calls are equivalent and call the same method in the object. In both the calls MATLAB passes obj as input to the method. Note the absence of obj as an argument in the dot notation. In dot notation obj, is added as an input argument before your args. In your code you are mixing both of these options. So you got two obj arguments for your method.
Relevant documentation is at http://www.mathworks.com/help/matlab/matlab_oop/method-invocation.html
Related
I want to run jobs in Matlab using batch, with parcluster. each job should use an existing class, and run one of it's methods. I can make It work without parcluster, but with parcluster I get an error.
without parpool, this works:
define a class with a simple method:
classdef myclass
properties
prop;
end
methods
% constructor
function obj = myclass()
obj.prop = 0;
end
% add function
function obj = add(obj,a)
obj.prop = obj.prop + a;
end
end
end
create an object and use it's function:
obj = myclass();
obj = add(obj,1);
this works. but when I try to run the same thing in batch I get an error. here is what I'm doing:
c = parcluster();
j = batch(c,#myclass,1,{});
wait(j);
r = fetchOutputs(j);
obj = r{1};
j = batch(c,#add,1,{obj,1});
the last line gives an error:
warning unable to calculate the dependencies of the files:
add
because: file, function or class "add" may not exist.
how can I run class methods in batch?
The most robust way of specifying a method of a class in an anonymous function is to use the dot notation
B = batch(c, #obj.add, 1, {1});
wait(B)
%// Re-assign results to obj (see note below)
obj = fetchOutputs(B);
This helps MATLAB to resolve myclass.add better as it is more explicit. The way that you had written it previously, MATLAB is looking for a regular function named add and is unable to find it. It does not consider the types of the input (which in your case would be required to know that it is a method).
Note: batch will make a copy of your object when you pass it as an input. Because of that, you will need to explicitly grab the output and re-assign to obj because the original obj will not be modified in-place.
I know that, inside a MATLAB function, inputname(k) will return the k-th argument iff the argument is a variable name. Is there any way to write some parsing code that can retrieve the full input argument when that argument is a structure, e.g. foo.bar ? The reason I want to be able to do this is that I'm writing some tools for generic use where the input could be either a named variable or a named structure element.
My primary intent is to be able to store and return the input argment(s) as part of a structure or other variable that the function returns. This is a 'chain of custody' feature which makes it easier for me or others to verify the source data sets used to generate the output data sets.
I don't want the user to have to self-parse externally, or to have to deal with some kludge like
function doit(name,fieldname)
if(exist('fieldname','var'))
name = name.(fieldname);
myinput = [inputname(1),inputname(2)];
else
myinput = inputname(1);
end
% do the function stuff
(I call this a kludge because it both requires the user to enter strange arguments and because it fouls up the argument sequence for functions with multiple inputs)
There is no support from the language to get the input names when passing structs. The reason is probably x.a is internally a call to subsref which returns a new variable, all context is lost. The only possibility you have is using the debug tools and parse the code. There is no other option.
function x=f(varargin)
[ST, I] = dbstack('-completenames', 1);
if numel(ST)>0
fid=fopen(ST(1).file,'r');
for ix=2:ST(1).line;fgetl(fid);end
codeline=fgetl(fid);
fclose(fid);
fprintf('function was called with line %s\n',codeline);
else
fprintf('function was called from base workspace\n');
end
end
From there you may try to parse the code line to get the individual argument names.
Far uglier than Daniel's approach, and probably will crash on the wrong OS, but here's a hack that works to retrieve the first argument; easily adjusted to retrieve all arguments.
[~,myname] = system('whoami');
myname = strtrim(myname(4:end)); % removes domain tag in my Windows envir
% sorry about " \' " fouling up SO's color parsing
myloc = ['C:\Users\' , myname , '\AppData\Roaming\MathWorks\MATLAB\R2015a\History.xml'] ;
f = fopen(myloc,'r');
foo = fscanf(f,'%s');
fclose(f);
pfoo = findpat(foo,'myFunctionName');
% just look for the last instance
namstart = find(foo(pfoo(end):(pfoo(end)+30)) =='(',1) +pfoo(end);
% catch either ')' or ','
namend(1) = find(foo((namstart):end)== ')',1) -2 +namstart;
if numel(find(foo((namstart):end)== ',',1)),
namend(2) = find(foo((namstart):end)== ',',1) -2 +namstart;
end
thearg = foo(namstart:(min(namend)) );
I have two functions, one is called from inside of another. I want certain parts of the first function to not execute when being called within the second function.
function vvec = vecVelocity(varargin);
%must be preceded with a 'syms var real' declaration where var is
%the parameter of your vector function
if nargin > 1 & nargin < 3
r = [sym(varargin(1:end))];
elseif nargin > 3
disp('too many inputs')
return
else r = [sym(varargin(1))];
end
if length(r) < 3
r = [r,0];
end
dr = diff(r);
uT = vecUnitTan(r);
speed = sqrt(sum(dr.^2));
v = speed*uT;
vvec = matlabFunction(v);
disp(['Simplified Symbolic Form: ' char(simplify(sym(vvec)))]);
I would like to suppress this last line disp(...) from appearing when I call this following second function from the command window
function speed = vecSpeed(r);
%must be preceded with a 'syms var real' declaration where var is
%the parameter of your vector function
v = sym(vecVelocity(r));
sp = sqrt(sum(v.^2));
speed = matlabFunction(sp);
disp(['Simplified Symbolic Form: ' char(simplify(sym(speed)))]);
At the moment, calling the vecSpeed function, causes a bunch of statements to be displayed from other preceding functions that are called from within the vecSpeed function (and some that are called from within the vecVelocity function), but I only want the disp(...) statement from the vecSpeed function to be called, not any of the others.
In the first function, you can put a block of codes in
if numel(dbstack) == 1
% Your code block
end
to prevent them to be executed unless the function is being called directly from Command Window.
Another way is to check for existence of some variables like debug_1, debug_2 etc.. which you can pass from the 2nd function when you call the 1st function.
I need some help for using varargin to assign properties in handle class.
Instead of using handle class, if I create a function with varargin, it works.
function out = testFunction(varargin)
% default values
startDate = '2011-11-01';
endDate = datestr(now,'yyyy-mm-dd');
% Map of parameter names to variable names
params_to_variables = containers.Map({'StartDate','EndDate'}, {'startDate','endDate'});
v = 1;
while v <= numel(varargin)
param_name = varargin{v};
if isKey(params_to_variables,param_name)
assert(v+1<=numel(varargin));
v = v+1;
% Trick: use feval on anonymous function to use assignin to this workspace
feval(#()assignin('caller',params_to_variables(param_name),varargin{v}));
else
error('Unsupported parameter: %s',varargin{v});
end
v=v+1;
end
end
But my current task is to create a super-class with many properties. There are various types of sub-classes. Different sub-class may need to use different properties. So when I create an instance of a super-class or sub-class, I need the input to be very flexible. As the example above, one sub-class only need the property 'startDate', and the other sub-class only need the property 'endDate'. Here is my code.
classdef superclass < handle
properties
startDate
endDate
end
methods
function obj = superclass(varargin)
% Map of parameter names to variable names
params_to_variables = containers.Map({'StartDate','EndDate'}, {'startDate','endDate'});
v = 1;
while v <= numel(varargin)
param_name = varargin{v};
if isKey(params_to_variables,param_name)
assert(v+1<=numel(varargin));
v = v+1;
feval(#()assignin('caller',params_to_variables(param_name),varargin{v}));
else
error('Unsupported parameter: %s',varargin{v});
end
v=v+1;
end
end
end
end
Basically I just copy and paste, it doesn't work.
So I change
feval(#()assignin('caller',params_to_variables(param_name),varargin{v}));
to
feval(#()assignin('caller',strcat('obj.',params_to_variables(param_name),varargin{v}));
or
feval(#()assignin('base',strcat('obj.',params_to_variables(param_name),varargin{v}));
or
evalin('caller',...
strcat('obj.',params_to_variables(param_name),'=',num2str(varargin{v})));
or
evalin('base',...
strcat('obj.',params_to_variables(param_name),'=',num2str(varargin{v})));
None of them works. If anyone can tell me how to solve this problem or provide me an alternative way, I appreciate it. Thank you.
Working on an assignment involving Genetic Algorithms (loads of headaches, loads of fun). I need to be able to test differing crossover methods and differing mutation methods, to compare their results (part of the paper I have to write for the course). As such, I want to just pass the function names into the Repopulate method, as function handles.
function newpop = Repopulate(population, crossOverMethod, mutationMethod)
...
child = crossOverMethod(parent1, parent2, #mutationMethod);
...
function child = crossOverMethod(parent1, parent2, mutationMethod)
...
if (mutateThisChild == true)
child = mutationMethod(child);
end
...
The key point here is like 3, parameter 3: how do I pass mutationMethod down another level? If I use the # symbol, I get told:
"mutationMethod" was previously used as a variable,
conflicting with its use here as the name of a function or command.
If I don't use the # symbol, then mutationMethod gets called, with no parameters, and is quite unhappy.
While I am aware that yes, I could just rewrite my code to make it work differently, I'm now curious as to how to make it actually work.
Any help is greatly appreciated.
Actually just dont use the # symbol, use it when you call the Repopulate function instead.
Example:
function x = fun1(a,m)
x = fun2(a,m);
end
function y = fun2(b,n)
y = n(b);
end
which we call as:
> fun1([1 2 3], #sum)
6
Refer to the documentation for Passing Function Handle Arguments
Note you can check if the argument is a function handle by: isa(m,'function_handle'). Therefore you can make your function Repopulate more flexible by accepting both a function handle and a function name as a string:
function x = fun(a,m)
if ischar(m)
f = str2func(m);
elseif isa(m,'function_handle')
f = m;
else
error('expecting a function')
end
x = fun2(a,f);
end
which now can be called both ways:
fun1([1 2 3], #sum)
fun1([1 2 3], 'sum')