I am writing a function and I need some help.
This is my function:
function [varargout] = myfunc(x, y, z, optional)
There are two possible outputs: A and B. By setting the compulsory input variables (x,y,z), you get A. If you also set the optional argument, you should get A and B as well.
So, this is the way I am trying to do it:
if (nargin == 4)
varargout{1} = A;
varargout{2} = B;
else
varargout{1} = A;
end
This is not working... Where am I making the mistake?
Thank you in advance!
I don't see a problem with it. The only problem will come if you attempt:
[a,b] = myfunc(1,2,3)
in which case your function will complain that you're trying to assign to a second variable that hasn't been defined. So you need to have some more input / output checking (e.g. via nargout) and act accordingly. (i.e. either specify a custom error, or return b=[], etc.
PS. I'm assuming your function is defined something like:
function varargout = myfunc(x, y, z, optional)
if (nargin == 4); varargout{1} = 1; varargout{2} = 2;
else varargout{1} = 1;
end
end
You need two outputs with varargout. Try this:
[A,varargout] = myfunc(x, y, z, optional)
and
if (nargin > 3)
varargout{1} = B;
end
There are a couple of issues with this code:
First, you haven't put the keyword "function" before declaring
myfunc.
Second, optional is set as the 4th argument. However, this way you
cannot include more than 4 arguments.
Third, you have to be careful with varargout, since it increases the
number of output argument, but it doesn't change the first one
(which is always equal to one).
I don't know which of the above was your main concern, however, the following code should be working:
function varargout = myfunc2(x, y, z, varargin)
if nargin == 4
varargout{1} = 1; % where A=1 and B = 2
varargout{2} = 2;
else
varargout{1} = 1;
end
end
Please have a look to the attached links for more details about varargin and varargout:
http://uk.mathworks.com/help/matlab/ref/varargin.html
http://uk.mathworks.com/help/matlab/ref/varargout.html
I solved it! I'll post here the solution, it could be useful for others. Thank you all!
function [A, varargout] = myfunc(x, y, z, optional)
A = somefunction(x,y,z)
if nargout == 2 && nargin == 4
i = find(A > optional);
B = somefunction(A,i);
varargout{1} = B;
end
In this way, you have an optional output associated to an optional input variable. It works :)
Related
I have a matlab function like:
function [f, fdx] = twice(x)
f = x * 2;
if nargout > 1
fdx = 2;
end
end
I want to call this function from another function, keeping the optional second-argument semantics. However, this is messy:
function [g, gdx] = twiceplusinverse(x)
% this starts to get messy if the arguments to double are long
if nargout > 1
[f, fdx] = twice(x);
else
f = double(x)
end
g = f + 1/x;
if narargout > 1
gdx = fdx + -1/x^2;
end
end
How can I avoid duplicating every function call that has multiple return values? What's a way to write the following that doesn't violate DRY?
if nargout > 1
[f, fda, fdb, fdc] = longfunction(some_func_producing_a(), b, another_func_for_c());
else
f = longfunction(somefunc_like_above(), b, another_func_for_c());
end
You can use varargout as the output of your function and then use a comma-separated list to assign the outputs of the other function. Since you use 1:nargout as the indices in the comma-separated list, the number of output arguments requested from your function will be passed onto the other function automatically.
function varargout = myfunc(x)
[varargout{1:nargout}] = other_func(x);
end
I have a simple function as below:
function dz = statespace(t,z)
dz = A*z + B*k*z
end
My main script is :
clear all;close all;format short;clc;
% step 1 -- input system parameters
% structure data
M1 = 1; M2= 1; M3= 1; %Lumped Mass(Tons)
M= diag([M1,M2,M3]);
k(1)= 980; k(2)= 980; k(3)= 980; %Stiffness Coefficient(KN/M)
K = zeros(3,3);
for i=1:2
K(i,i)=k(i)+k(i+1);
end
K(3,3)=k(3);
for i=1:2
K(i,i+1)=-k(i+1);
end
for i=2:3
K(i,i-1)=-k(i);
end %Stiffness Matrix(KN/M)
c(1)= 1.407; c(2)= 1.407; c(3)= 1.407; %Damping Coefficient(KN.sec/M)
C = zeros(3,3);
for i=1:2
C(i,i)=c(i)+c(i+1);
end
C(3,3)=c(3);
for i=1:2
C(i,i+1)=-c(i+1);
end
for i=2:3
C(i,i-1)=-c(i);
end %Damping Matrix(KN.sec/M)
A = [zeros(3) eye(3);-inv(M)*K -inv(M)*C]
H = [1;0;0]
B = [0;0;0;inv(M)*H]
k = [-1 -1 -1 -1 -1 -1]
t = 0:0.004:10;
[t,z] = ode45(statespace,t);
When I run my main script it comes with following error:
Undefined function or variable 'A'.
Error in statespace (line 2)
dz = A*z + B*k*z
As you can see I defined A in main script. Why this problem happening?
There multiple things wrong with your code. First, you need to supply the values of A and B to your function but as you are invoking it (incorrectly without the # and additional parameter y0 as I commented below) in the toolbox ode45, you have to keep just two parameters so you cannot supply A and B as additional parameters. If you define A and B within your function or share them via global variables you will get further. However, as noted below the definitions don't seem to be correct as A * z and B * k * z don't have the same dimensions. z is a scalar so B * k needs to be same size and shape as A which currently it is not.
Edit from:
As Jubobs suggested change your function's parameters to include A, B and k. Also you don't need t as it is never used in the function. So:
function dz = statespace(A, B, k, z)
dz = A*z + B*k*z
end
As others have pointed out, A, B and k are not defined in the function workspace, so you either need to define them again (ugly, not recommended), declare them as global variables (slightly better, but still not good practice), or pass them as arguments to your function (the better solution). However, because you then want to use the function with ode45, you need to be a bit careful with how you do it:
function dz = statespace(t,z,A,B,k)
dz = A*z + B*k*z
end
and then the call to ode45 would like this:
[t,z] = ode45(#(t,z)statespace(t,z,A,B,k),[0 Tf],z0); % where Tf is your final time and z0 your initial conditions
See Error using ode45 and deval for a similar problem.
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.
I have a function with a variable number of arguments and outputs, and I want it to exit at a certain point if there is an additional argument:
function [out, varargout] = myfunction(a,varargin)
% do stuff
out = 1;
if nargin > 1
return
end
% do extra stuff if there is no additional argument
varargout{1} = 'optional output';
end
I get the error
Output argument "varargout" not assigned during call to "C:\...\myfunction"
How can I solve this?
How about something like this?
function varargout = my_function(a,varargin)
% do stuff
varargout{1} = 1;
if nargin > 1
if nargout > 1
varargout(2:nargout) = {[]};
end
return
end
% do extra stuff if there is no additional argument
varargout{2} = 'optional output';
end
Test:
[a b] = my_function(2)
a =
1
b =
optional output
[a b] = my_function(2,3)
a =
1
b =
[]
The problem is, you can't call a function with more outputs than it creates. Therefore, calling you original function a = my_function(2,3) would work fine, while [a b] = my_function(2,3) will cause an error.
Thus you have (at least) two alternatives:
Make sure the number of output and input variables match every time you execute the function.
Do as I did above.
I have a function
function toto(a,b)
[out,~] = evalc(a)
% here I would like to call another function
myFunc(x,y,file);
end
How could I pass this function as args to toto function as sometimes I want to call toto(a,b) and some other times toto(a,b,#()myFunc(x,y) ?
(Answer before question edit: assumes fixed number of inputs to toto)
If you want to call an arbitrary function from within function toto: first define a handle to that function:
f = #myFunc;
and then pass that handle as input argument to toto, so that you can use it within toto:
function toto(a,b,f)
[out,~] = evalc(a)
f(x,y,file); %// call function whose handle is f
end
Define your function with an input to pass a function handle:
function toto(a,b,fun)
...
% You must know how many inputs and outputs to expect
% but nargin and nargout do work for function handles
% so you can handle different cases if needed.
[y1,y2,...] = fun(x1,x2,...);
...
Call the function and pass in a handle to the function:
toto(a,b,#FunName)
Or:
FunHandle = #FunName;
toto(a,b,FunHandle)
You can pass in additional parameters by using an anonymous function:
Param = 'FileName';
AnonFunHandle = #(x1,x2)FunName(x1,x2,Param);
toto(a,b,AnonFunHandle)
If you want to be able to use both the toto(a,b) and toto(a,b,f) or similar function calls, you need to use varargin and nargin (and their output counterparts). Here is a very basic example; it ignores any more than two outputs or any more than three inputs, and does not do any input checking etc.
function [vargout] = toto(a,b,varargin)
if nargin >2
func = vargin{1};
fout = func(a,b);
else
fout = [] % if no third argument is given returns empty
end
if nargout > 0
varargout{1} = a+b;
end
if nargout > 1
varargout{2} = fout;
end
end
So for example you can call this as x = toto(2,3) (returns x = 5), [x y] = toto(2,3) (returns x = 5, y = []), [x y] = toto(2,3,#(x,y)(x*y)) (returns x = 5, y = 6).