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.
Related
I am trying to calculate the integral of a function in Matlab and Mathematica that the software cannot do symbolically.
Here is my MatLab code so far, but I understand it may not be very helpful as is.
f = #(t) asin(0.5*sin(t));
a = #(t) sin(t);
F = int(f,t) % Matlab can't do this
F =
int(asin(sin(t)/2), t)
A = int(a,t) % This works
A =
-cos(t)
dt = 1/(N-1); % some small number
for i=1:N
F(i) = integral(f,(i-1)*dt,i*dt);
A(i) = integral(a,(i-1)*dt,i*dt);
end
Both of the calculations in the for loop give a rough approximation of f or a not their integrals after multiplying by dt.
On the math stack-exchange I found a question that derives a finite difference like method for the integral at a point. However, when I did the calculation in Matlab it output a scaled down version of f which was evident after plotting (see above for what I mean by scaled down). I think that's because for smaller intervals the integral basically approximates the function to varying degrees of accuracy (again see above).
I am trying to get either a symbolic equation for the integral, or an approximation of the integral of the function at each location.
So my question is then if I have a function f that MatLab and Mathematica cannot easily take the integral of
can I approximate the integral directly with an integral calculator besides the default ones? (int,integral,trapz)
or
can I approximate the function with finite differences first and then evaluate the integral symbolically?
Your code is nearly fine it's just that
for i=1:N
F(i) = integral(f,0,i*dt);
end
You could also do
F(1)=integral(f,0,dt)
for i=2:N
F(i) = F(i-1)+integral(f,(i-1)*dt,i*dt);
end
Second option is surely more efficient
Because the primitive is really F(x)=int(f(x), 0, x) (0 defines a certain constant ) and for sufficiently small dx you have shown that f(x)=int(f(x), x,x+dx)/dx i. You have proven that MATLAB intégral function does its job.
For example let's take = the function above will compute if you wish to compute just replace 0 above by the constant a you like.
now and so you should get F containing a discretization of
The accepted answer in general is by far the best method I would say but if certain restrictions on your functions are allowable then there is a second method.
For two functions f and g see below
T = 1; % Period
NT = 1; % Number of periods
dt = 0.01; % time interval
time = 0:dt:NT*T; % time
syms t
x = K*sin(2*pi*t+B); % edit as appropriate
% f = A/tanh(K)*tanh(K*sin(2*pi*t+p))
% g = A/asin(K)*asin(K*sin(2*pi*t+p))
formulas found here
f = A1/tanh(K1)*(2^(2*1)-1)*2^(2*1)*bernoulli(2*1)/factorial(2*1)*x^(2*1-1);
% |K1|<pi/2
g = A2/asin(K2)*factorial(2*0)/(2^(2*0)*factorial(0)^2*(2*0+1))*x^(2*0+1);
% |K2|<1
there are no such limitations in the accepted answer
N = 60;
for k=2:N
a1 = (2^(2*k)-1)*2^(2*k)*bernoulli(2*k)/factorial(2*k);
f = f + A1/tanh(K1)*a1*x^(2*k-1);
a2 = factorial(2*k)/(2^(2*k)*factorial(k)^2*(2*k+1));
g = g + A2/asin(K2)*a*x^(2*k+1);
end
MATLAB can calculate sin^n(t) for n being an integer.
F = int(f,t);
phi = double(subs(F,t,time));
G = int(g,t);
psi = double(subs(G,t,time));
In the integral
I want to optimize the function Dt, as I know the end result of the integral. I have expressions for k1 and k0 in terms of k2 and N, and it is k2 and N that I would like to optimize. They have constraints, needing to be between certain values. I have it all setup in my code, but I am just unaware of how to tell the genetic alogrithm to optimize an integral function? Is there something I'm missing here? The integral is usually evaluated numerically but I am trying to go backwards, and assuming I know an answer find the input parameters
EDIT:
All right, so here's my code. I know the integral MUST add up to a known value, and I know the value, so I need to optimize the variables with that given parameter. I have created an objective function y= integral - DT. I kept theta as syms because it is the thing being integrated to give DT.
function y = objective(k)
% Define constants
AU = astroConstants(2);
mu = astroConstants(4);
% Define start and finish parameters for the exponential sinusoid.
r1 = AU; % Initial radius
psi = pi/2; % Final polar angle of Mars/finish transfer
phi = pi/2;
r2 = 1.5*AU;
global k1
k1 = sqrt( ( (log(r1/r2) + sin(k(1)*(psi + 2*pi*k(2)))*tan(0)/k(1)) / (1-
cos(k(1)*(psi+2*pi*k(2)))) )^2 + tan(0)^2/k(1)^2 );
k0 = r1/exp(k1*sin(phi));
syms theta
R = k0*exp(k1*sin(k(1)*theta + phi));
syms theta
theta_dot = sqrt((mu/(R^3))*1/((tan(0))^2 + k1*(k(1))^2*sin(k(1)*theta +
phi) + 1));
z = 1/theta_dot;
y = int(z, theta, 0,(psi+2*pi*k(2))) - 1.3069e08;
global x
x=y;
end
my k's are constrained, and the following is the constraint function. I'm hoping what I have done here is tell it that the function MUST = 0.
function [c,c_eq] = myconstraints(k)
global k1 x
c = [norm(k1*(k(1)^2))-1 -norm(k1*(k(1)^2))];
c_eq =[x];
end
And finally, my ga code looks like this. Honestly, I've been playing with it all night and getting error messages after error messages - ranging from "constraint function must return real value" to "error in fcnvectorizer" and "unable to convert expression into double array", with the last two coming after i've removed the constraints.
clc; clear;
ObjFcn = #objective;
nvars = 2
LB = [0 2];
UB = [1 7];
ConsFcn = #myconstraints;
[k,fval] = ga(ObjFcn,nvars,[],[],[],[],LB,UB,ConsFcn);
I've been stuck on this problem for weeks and have gotten nowhere, even with searching through literature.
I want to Calculating the value of a function for different inputs in matlab and insert output in a matrix for example: x(1,1)=1 y(1,1)=1 x(1,2)=2 y(1,2)=4 and etc.
this is my m file in matlab:
clc,clear all,close all
x0=0;
xn=10;
n=10;
h=(xn-x0)/n;
k=1;
for k=1:n
x=[1:10];
x=x0+h;
y=x^2
x0=x;
end
My problem is that every time the for loop runs The output value is stored in the y and I can't use the output value for example: x=2 in somewhere else.
A few thoughts:
x=[1:10] does not do anything as you overwrite it in the next line
If you remove x = [1:10] you can achieve what you want to achieve by using indexing, i.e. x(k) = x0 + h and y(k) = x(k)^2 and x0 = x(k)
There is a simpler way though using vectorization though!
x = 1:10
y = x.^2
I'd like to compute kernel matrices efficiently for generic kernel functions in
Matlab. This means I need to compute k(x,y) for every row x of X
and every row y of Y. Here is some matlab code that computes what I'd
like, but it is rather slow,
function K=compute_kernel( k_func, X, Y )
m = size(X,1);
n = size(Y,1);
K = zeros(m,n);
for i = 1:m
for j = 1:n
K(i,j) = k_func(X(i,:)', Y(j,:)');
end
end
end
Is there any other approach to this problem, e.g. some bsxfun variant that
calls a function on every row taken from X and Y?
pdist2(X,Y, dist_func) unfortunately computes dist_func(X, Y(i,:)), instead of dist_func(X(i,:), Y(i,:)). So the actual function I need is,
function K=compute_kernel( k_func, X, Y )
% Woohoo! Efficient way to compute kernel
size(X)
size(Y)
m = size(X,1);
n = size(Y,1);
for i = 1:n
K(:,i) = pdist2( Y(i,:), X, k_func);
end
It's not as nice as just using pdist2, but is still much more efficient than the previous case.
Have you tired pdist2 with custom distance function?
P.S.
It is best not to use i and j as variables in Matlab
My problem has 60 variables (x1 to x60) and here is the function:
f=(x1+x2+x3)*x1+(x2+x3+x4)*x2+...+(x58+x59+x60)*x58
I want to get the Hessian matrix of the function f. However, because there are so many variables, I don't want to write them one by one for syms and f.
I know I can manually calculate the Hessian matrix of the function f as the function is not too difficult. However, I occasionally need to change the form of the function, such as changing the function to (increase the number of variables in the brackets):
f=(x1+x2+x3+x4)*x1+(x2+x3+x4+x5)*x2+...+(x57+x58+x59+x60)*x57
Therefore, I don't want to manually compute the Hessian matrix of function f as long as the function form changes. Is there any easier way to use syms to write f with these 60 variables in MATLAB so that I can use hessian to get the Hessian matrix of f?
First, given the regular and simple nature of the function f described, your Hessian has a defined structure that can be directly calculated numerically. Like this, for example:
n = 60; % number of variables
b = 3; % number of terms in parentheses
h = diag(2+zeros(n,1));
for i = 1:b-1
d = diag(ones(n-i,1),i);
h = h+d+d.';
end
h(n-b+2:n,n-b+2:n) = 0
This can be done without a for loop via something like this:
n = 60; % number of variables
b = 3; % number of terms in parentheses
h = full(spdiags(repmat(ones(n,1),1,2*b-1),1-b:b-1,n,n)+speye(n));
h(n-b+2:n,n-b+2:n) = 0
Symbolically, you can create a vector of variables with sym to create your function and calculate the Hessian like this:
n = 60; % number of variables
b = 3; % number of terms in parentheses
x = sym('x',[n 1]); % vector of variables
f = 0;
for i = 1:n-b+1
f = f+sum(x(i:i+b-1))*x(i);
end
h = hessian(f,x)
It's possible to remove the for loops, but there won't be much performance benefit.