I have two Matlab functions f=fun1(x) and f=fun2(x,y) which are very alike and I would like to integrate them into a single function f=fun(x,y).
For the first function I have
function f=fun1(x)
N=1000; % Some large number.
for j=1:N
f=x^2;
end
and for the second function
function f=fun2(x,y)
N=1000; % Some large number.
for j=1:N
f=x^2;
f=f+y;
end
. So actually fun1 is sort of a subfunction of fun2. I would like to construct a function f=fun(x,y,method_number) like
function f=fun(x,y,method_number)
N=1000; % Some large number.
for j=1:N
f=x^2; % If method_number==1 run only this command....
f=f+y; % If method_number==2 run also this command.
end
This is just a short simplified example of the problem I want to solve. My real problem is that I have three long functions f=fun1(x,y,z), f=fun2(x,y) and f=fun3(x) with several resemblances and of which fun3 is a subfunction of fun2 and fun2 is a subfunction of fun1 in the same meaning as here above. I do not believe using switch-case or if-else everywhere is an option since N can be very large, which would be inefficient. Furthermore, it would completely destroy the layout of the code.
In your case it seem each of your function have a different number of input argument. If it is the case, the matlab function nargin can detect that and you do not have to specify an additional method parameter.
For example:
function f = fun(x,y,z)
switch nargin
case 1
f = x.^2; %// run only if ONE argument was specified
case 2
f = fun(x) + y; %// run only if TWO arguments were specified
case 3
f = fun(x,y) ./ z ; %// run only if THREE arguments were specified
otherwise
disp('Houston, we have a problem !!') ; %// run if NO or more than 3 arguments were specified
end
You can call f with one argument, two or three without trouble, Matlab will only execute the function corresponding to the proper number of argument.
The function, when passed with 3 arguments, can call on itself to calculate the part with 2 argument (which can call on itself to calculate the part from the first argument).
Case two: If the recursion really cannot be taken out of the loop, the classic if ... then will work:
function f = fun(x,y,z)
if nargin == 3
threeArgs = true ;
twoArgs = true ;
elseif nargin == 2
threeArgs = false ;
twoArgs = true ;
elseif nargin == 1
threeArgs = false ;
twoArgs = false ;
end
for it=1:1e6
f = x.^2; %// If method_number==1 run only this command....
%// ... other computations
if twoArgs
f = f + y ; %// If method_number==2 run also this command.
%// ... other computations
if threeArgs
f = f ./z ; %// If method_number==3 run also this command.
%// ... other computations
end
%// ... other computations only relevant to f(x,y)
end
%// ... other computations only relevant to f(x)
end
This would totally exclude recursion and would insure the minimum number of computation.
Now I realise this looks a bit clumsy code and you asked for a solution without if ... then and switch. Depending on your calculation, there is a method which can avoid any if or switch but may not be practical for all cases.
The idea is to assign an invariant operator to y or z in case they are not called.
Example:
function f = fun(x,y,z)
if nargin < 3 ; z = 1 ; end
if nargin < 2 ; y = 0 ; end
for it=1:1e6
f = x.^2;
%// ... other computations just based on X
f = f + y ; %// This always run, but if "y" wasn't specified, it does not modify the result (f+0=f)
%// ... other computations
f = f ./z ; %// This always run, but if "z" wasn't specified, it does not modify the result (f./1=f)
%// ... other computations
end
This avoid any flow branch in the code but i would only keep this method for simple cases, because the computations are always done regardless of the case (although may be some JIT compiler are smart enough to not bother doing 'no effect' operations).
You can avoid checking for the number of input arguments nargin N-times by duplicating code. You will check once, which computation should be done and repeat it N times. In this example, the for-loop is the duplicated code. To some extent, this might be okay.
function f = fun(x, y, z)
N = 1000;
switch nargin
%// Do something if only x is given
case 1
for j = 1:N
f = x.^2;
end
%// Do something else if only x and y are given
case 2
for j = 1:N
f = x.^2 + y;
end
%// Do something else if x, y and z are given
case 3
for j = 1:N
f = x.^2 + y - z;
end
otherwise
error('Use fun.m with 1, 2 or 3 arguments only!');
end
end
This is a variation of Hoki`s answer. In fact, I started from it adding the for-loop and removing the recursive function calls by adding duplicated code.
Related
The C code that finds the following integral according to the Simpson's 1-3 (h / 3) method is given below. Fill in the blanks on the code appropriately.
I want to solve this question below in Matlab but i didn't do it. This is simple question but i can't do it. If someone will help me, i will be very happy.
C code version
[C code version2
I tried this code block in Matlab:
% Ask for user input
% Lower bound (a)
a = input('What is your lower bound (a)?')
% Upper bound (b)
b = input('What is your upper bound (b)?')
% Subintervals
N = input('How many subintervals (N)?')
% Defining function
f = #(x,e) (e*x+sin(x))
% Finding h
h=(b-a)/N;
% Finding the values of x for each interval
x=linspace(a,b,N);
% Calculating the integral
for i = 1:N-1
I(i)= (h/3)*(f(x(i))+(4*f((x(i)+x(i+1))/2))+f(x(i+1)));
end
answer1 = sum(I)
disp(I)
% adding f(b) to sum
val2=ff(length(xx));
sum=val1+val2+sum;% set sum
% set result
result=sum*h/3;
Note that MATLAB does not use the symbol e as Neperian Number (Euler's number). To produce Euler's number in MATLAB, you can use exponential function exp(x), e = exp(1),
Therefore, First, correct your function definition:
F = #(x) exp(1).^x + sin(x) % Always try to use Upper-Case letters for your variable/function name
Then, you can use the following snippet to calculate the Integral using Simpson's 1/3:
a = 0; b = 3; N = 1e4;
F = #(x) exp(1).^x + sin(x);
h = ((b-a)/2)/N;
x = linspace(a,b,N);
I = 0;
for i = 1:N-1
I = I + h/3*(F(x(i)) + 4*F((x(i)+x(i+1))/2) + F(x(i+1)));
end
disp(I)
% To compare your result:
Itz = trapz(x, F(x))
I tried to test with my really simple code as below, but the error is "Too many output arguments."
function func1(x,y)
plot(x, y), xlabel('x'), ylabel('Sin(x)'), title('Sin(x) Graph'),
grid on, axis equal
end
function func2(x,y)
plot(x, y), xlabel('x'), ylabel('Cos(x)'), title('Cos(x) Graph'),
grid on, axis equal
end
the main is
x = 0:0.01:10;
y1 = sin(x);
y2 = cos(x);
funcs = {#func1, #func2} ; % let fun1, fun2 be two functions
arguments = {x y1;x y2} ; % write the inputs of each function
solutions = cell(1,2); % initialize the solution
% use of parfor
parfor ii = 1:2
solutions{ii}=funcs{ii}(arguments{ii,:});
end
Please help!!!
The way you call the function
solutions{ii}=funcs{ii}(arguments{ii,:});
Expects an output, which you're assigning to solutions{ii}.
This wouldn't work within a normal loop, or even without a loop, the fact that you're trying to write a parfor is immaterial here...
Your functions are defined as
function func1(x,y)
% ...
function func2(x,y)
% ...
Neither of these have output arguments, so it's unclear what you expect to be assigning to solutions{ii} - this exactly matches the error message you're seeing "too many output arguments".
If you expect an output from your function, then declare one
function z = func1(x,y)
z = x + y;
% other stuff
end
Otherwise, don't request an output within the loop
parfor ii = 1:2
funcs{ii}(arguments{ii,:});
end
I am trying to integrate a function F which is defined as:
function F
x = -3:0.1:3;
F = zeros(1, length(x));
for i = 1:length(x)
if (1.4<= x(i)) && (x(i) <= 1.6)
F(i) = x(i).^2;
else
F(i) = 2;
end
end
end
but the integral function gives me an error saying that there are too many arguments. I think the problem that the function is defined as a points?
The problem with your function, is that integral has no way to pass the arguments you supply to your function F. The function doesn't know that it can just pull certain elements from the vector you created. If you rewrite your function such that for an input (or x value), the output of F is returned, then integral will work as you need given two values to integrate between.
Matlab introduced for the ~ character in the list of output arguments of some routine in order to indicate we're not interested in this output value. For instance:
% Only interested for max position, not max value
[~, idx] = max(rand(1, 10));
For speed optimization reasons, is it possible from inside some routine to detect that some of the output arguments are not used ? For instance:
function [y, z] = myroutine(x)
%[
if (argout(1).NotUsed)
% Do not compute y output it is useless
y = [];
else
% Ok take time to compute y
y = timeConsummingComputations(x);
end
...
%]
It may not be the best one but an easy solution is to add another input argument
function [y, z] = myroutine(x, doYouWantY)
%[
if doYouWantY == 0
% Do not compute y output it is useless
y = [];
else
% Ok take time to compute y
y = timeConsummingComputations(x);
end
...
%]
nargout method, edited for 2nd output. Not very stable solution though, since whenever you call the function with one output argument, you need to be aware that the output is the second argument only.
function [y, z] = myroutine(x)
%[
if nargout==1
% Do not compute y output it is useless
y = [];
else
% Ok take time to compute y
y = timeConsummingComputations(x);
end
%]
I have a 4 by 3 matrix ('mymatrix'). myfunc inputs 'mymatrix' and outputs 'result'. I am using myfunc in a loop (for 17280 times) in my script. So, each time, it redefines syms x y z t. Is there a way to take 'syms x y z t' outside myfunc. It takes 0.004 second to initialize in each time.
function result = myfunc(mymatrix)
tic
syms x y z t
toc
f = 3*x+5*y-6*z+7;
eqn = subs(f,{x,y,z},{mymatrix(:,1)*t,mymatrix(:,2)*t,mymatrix(:,3)*t});
for ii = 1:4
result(ii,1) = solve(eq(ii))
end
PS: I also tried to vectorize for loop but could not succeed. If you can, I will be glad.
You can declare the symbolic variables to be persistent during the execution:
function result = myfunc(mymatrix)
persistent x y z t
if isempty(x)
syms x y z t
end
...
end
This results in about a 10% decrease in execution time on my machine (0.65-ish to 0.59-ish from the profiler).
However, as #Divakar pointed out in the comments, since results is numeric and not symbolic, a massive performance boost can be obtained by switching to a numeric solver like fsolve or fzero (only fzero is posted here since it was faster and is part of the basic MATLAB suite):
function result = myfunc(mymatrix)
A = mymatrix*[3;5;-6];
f = #(t,k) A(k,:)*t + 7;
N = size(A,1);
result(N,1) = 0;
for k = 1:N
result(k) = fzero(#(t) f(t,k),0);
end
end
On my machine, this function runs in 0.02-ish seconds, 30 times faster than the symbolic approach.