Symbolic int results in deletion of main variable (MATLAB) - matlab

I am trying to do something like this:
syms x h4 t4 c13;
t = 0.6*sin(pi*x);
h1x = 0.5*(1 - t);
h0 = h1x;
h14x = -h4 -t4*(x - 0.5);
h24x = h4 + t4*(x - 0.5);
symvar(h14x)
which returns
ans =
[ h4, t4, x]
Then
u13x = (-4*int(h14x, x, 0, x) + c13)/h0
symvar(u13x)
returns
u13x =
-(c13 + 4*x*(h4 - t4/2) + 2*t4*x^2)/((3*sin(pi*x))/10 - 1/2)
ans =
[ c13, h4, t4, x]
and
p12x = -3*int(u13x, x, 0, x)
symvar(p12x)
which is
p12x =
-3*int(-(c13 + 4*x*(h4 - t4/2) + 2*t4*x^2)/((3*sin(pi*x))/10 - 1/2), x, 0, x)
ans =
[ c13, h4, t4 ]
As you can see from u13x where the variables were [h4, t4, c13, x], while integrating to p12x it got reduced to [h4, t4, c13] even though the integral limits are variable (in terms of x). Is it a bug? I can't seem to get by this weird behaviour. Is there a workaround?

Here are three possible workarounds (tested in R2015a).
1. Use a symbolic function
One option is to make the input that will be passed to sym/symvar a symfun in terms of x and then use the optional second argument to specify a finite number of variable to look for:
syms x h4 t4 c13;
t = 0.6*sin(pi*x);
h1x = 0.5*(1 - t);
h0 = h1x;
h14x = -h4 -t4*(x - 0.5);
u13x = (-4*int(h14x, x, 0, x) + c13)/h0
p12x(x) = -3*int(u13x, x, 0, x) % Make symfun, function of x
n = realmax; % 4 or greater to get all variables in this case
symvar(p12x, n) % Second argument must be finite integer
which returns the expected [ x, t4, h4, c13]. Just setting the second argument to a very large integer value seems to work.
2. Convert expression to a string
There are actually two versions of symvar. There is symvar for string inputs and sym/symvar, in the Symbolic Math toolbox, for symbolic expressions. The two forms apparently behave differently in this case. So, another workaround is to convert the equation with int to a character string with sym/char before passing it to symvar and then converting the output back to a vector of symbolic variables:
syms x h4 t4 c13;
t = 0.6*sin(pi*x);
h1x = 0.5*(1 - t);
h0 = h1x;
h14x = -h4 -t4*(x - 0.5);
u13x = (-4*int(h14x, x, 0, x) + c13)/h0
p12x = -3*int(u13x, x, 0, x)
sym(symvar(char(p12x))).'
which also returns the expected [ c13, h4, t4, x] (note that order appears to be opposite of the first workaround above).
3. Call MuPAD function from Matlab
Lastly, you can call the MuPAD function indets that finds indeterminates in an expression.
syms x h4 t4 c13;
t = 0.6*sin(pi*x);
h1x = 0.5*(1 - t);
h0 = h1x;
h14x = -h4 -t4*(x - 0.5);
u13x = (-4*int(h14x, x, 0, x) + c13)/h0
p12x = -3*int(u13x, x, 0, x)
feval(symengine, 'x->indets(x) minus Type::ConstantIdents', p12x)
which returns [ x, c13, h4, t4]. This will work if the input p12x is class sym or symfun. You can also use:
evalin(symengine, ['indets(hold(' char(p12x) ')) minus Type::ConstantIdents'])
The reason that sym/symvar doesn't work in your case is because it is based on freeIndets under the hood, which explicitly ignores free variables in functions like int.

Related

Error while evaluating the function convolution

This is my first attempt to write anything in matlab, so please, be patient.
I am trying to evaluate the solution of the following ODE: w'' + N(w, w') = f(t) with the Cauchy conditions w(0) = w'(0) = 0. Here N is a given nonlinear function, f is a given source. I also need the function
where G is the solution of the following ODE:
where G(0) = G'(0) =0, s is a constant, and
My try is as follows: I define N, f, w and G:
k = 1000;
N = #(g1,g2) g1^2 + sin(g2);
f = #(t) 0.5 * (1 + tanh(k * t));
t = linspace(0, 10, 100);
w = nonlinearnonhom(N, f);
G = nonlinearGreen(N);
This part is ok. I can plot both w and G: both seems to be correct. Now, I want to evaluate wG. For that purpose, I use the direct and inverse Laplace transforms as follows:
wG = ilaplace(laplace(G, t, s) * laplace(f, t, s), s, t);
but is says
Undefined function 'laplace' for input arguments of type 'double'.
Error in main (line 13)
wG = ilaplace(laplace(G, t, s) * laplace(f, t, s), s, t);
Now, I am not sure if this definition of wG is correct at all and if there are not any other definitions.
Appendix: nonlinearGreen(N) is defined as follows:
function G = nonlinearGreen(N)
eps = .0001;
del = #(t)[1/(eps * pi) * exp( -t^2/eps^2)];
eqGreen = #(t, g)[g(2); - N(g(1),g(2)) + del(t)];
tspan = [0, 100];
Cc = [0, 0];
solGreen = ode45(eqGreen, tspan, Cc);
t = linspace(0, 10, 1000);
G = deval(solGreen, t, 1);
end
and nonlinearnonhom is defined as follows:
function w = nonlinearnonhom(N, f)
eqnonhom = #(t, g)[g(2); - N(g(1),g(2)) + f(t)];
tspan = [0, 100];
Cc = [0, 0];
solnonhom = ode45(eqnonhom, tspan, Cc);
t = linspace(0, 10, 100);
w = deval(solnonhom, t, 1);
end
You keep mixing different kind of types and it's not a good idea. I suggest you keep with symbolic all the way if you want to use the laplace function. When you define N and f with #(arobase) as function handles and not symbolic expressions as you might want to do. I suggest you have a look at symbolic documentation and rewrite your functions as symbolic.
Then, the error message is pretty clear.
Undefined function 'laplace' for input arguments of type 'double'.
Error in main (line 13)
wG = ilaplace(laplace(G, t, s) * laplace(f, t, s), s, t);
It means that the function laplace can't have arguments of type double.
The problem is that your t is a vector of double. Another mistake is that s is not defined in your code.
According to Matlab documentation of laplace, all arguments are of type symbolic.
You can try to manually specify symbolic s and t.
% t = linspace(0, 10, 100); % This is wrong
syms s t
wG = ilaplace(laplace(G, t, s) * laplace(f, t, s), s, t);
I have no error after that.

How to determine the size of an input argument for a function handle

I am creating a function that takes in data (x,y,z) and an anonymous function (M) as inputs. M's inputs are data (x,y,z) and a parameter (theta).
I need to determine the dimension of the parameter theta inside FUNC
EDIT: (To add some context)
I have data that follows a known data generating process (DGP). For example, I can generate data using a linear instrumental variable DGP with 1 endogenous variable (hence theta will be dimension 1):
n = 100; q = 10;
theta0 = 1; % true param value
e = randn(n, 1); % 2nd stage error
u = randn(n, 1); % 1st stage error
z = randn(n, q); % instrument
x = z * ones(q, 1) + u; % endog variable
y = x * theta0 + e; % dependent variable
Then I want to estimate theta0 using my own variation of generalized linear methods (FUNC)
M = #(x,y,z,theta) z' * (y - x * theta); % moment condition
thetahat = FUNC(M, x, y, z); % estimate theta0
and FUNC.m is
function out = FUNC(M, x, y, z)
k = ; % (!!!) <-- this is what I need to find out!
objFunc = #(theta) M(x, y, z, theta)' * M(x, y, z, theta);
out = fminunc(objFunc, ones(1, k)); % <-- this is where its used
end
In the above example, the DGP is a linear IV model. However, I should be able to use my function for any other DGP.
Other DGPs could, for example, define M as follows:
% E.g. 1) theta is dimension 1
M=#(x,y,z,theta) z' * (y - x * theta);
% E.g. 2) theta is dimension 2
M=#(x,y,z,theta) z' * (y - (x * theta(1))^theta(2));
% E.g. 3) theta is dimension 3
M=#(x,y,z,theta) z' * (y - (theta(1) + x * theta(2))^theta(3));
The (super bad) hack that I am currently using for (!!!) is:
for ktest = [3,2,1] % the dimension of theta will never be higher than 3
try
M(x, y, z, ones(1, ktest);
k = ktest;
end
end
Since you know already what the form and requirements of your function M will be when you pass it to FUNC, it doesn't make much sense to then require FUNC to determine it based only on M. It would make much more sense to pass flag values or needed information to FUNC when you pass it M. I would write FUNC in one of two ways:
function out = FUNC(M, x, y, z, k) % Accept k as an argument
...
end
function out = FUNC(M, x, y, z, theta0) % Pass the initial guess, of the correct size
...
end
If you really want to let FUNC do the extra work, then the answer from excaza is how I would do it.
Old answer below. not really valid since the question was clarified, but I'm leaving it temporarily...
I think you have two better options here...
Make M a cell array of anonymous functions:
You could make your input M a cell array of possible anonymous functions and use the number of values in theta as the index. You would pass this M to FUNC:
M = {#(x,y,z,theta) z' * (y - x * theta), ...
#(x,y,z,theta) z' * (y - (x * theta(1))^theta(2)), ...
#(x,y,z,theta) z' * (y - (theta(1) + x * theta(2))^theta(3))};
Then somewhere inside FUNC:
out = M{numel(theta)}(x, y, z, theta);
Make M a normal function instead of an anonymous one:
An anonymous function is good for quick, simple formulas. Add in conditional logic and you should probably just make it a fully-fledged function. Here's an example with a switch statement (good for if you have a number of different formulas):
function out = M(x, y, x, theta)
switch numel(theta)
case 1
out = z' * (y - x * theta);
case 2
out = z' * (y - (x * theta(1))^theta(2));
case 3
out = z' * (y - (theta(1) + x * theta(2))^theta(3));
end
end
And here's an example that sets some defaults for parameters (good for if you have one formula with different ways to set its parameters, like you seem to have):
function out = M(x, y, x, theta)
switch numel(theta)
case 1
p1 = 0;
p2 = theta;
p3 = 1;
case 2
p1 = 0;
p2 = theta(1);
p3 = theta(2);
case 3
p1 = theta(1);
p2 = theta(2);
p3 = theta(3);
end
out = z' * (y - (p1 + x * p2)^p3);
end
MATLAB doesn't store any information about the size of the inputs to an anonymous function. While a better idea would be to modify your code so you don't have to do these kinds of gymnastics, if your function definition is known to fit a narrow band of possibilities you could use a regular expression to parse the function definition itself. You can get this string from the return of functions.
For example:
function [nelements] = findsizetheta(fh)
defstr = func2str(fh);
test = regexp(defstr, 'theta\((\d+)\)', 'tokens');
if isempty(test)
% Assume we have theta instead of theta(1)
nelements = 1;
else
nelements = max(str2double([test{:}]));
end
end
Which returns 1, 2, and 3 for your example definitions of M.
This assumes that theta is present in you anonymous function and that it is defined as a vector.
Also note that MATLAB cautions against utilizing functions in a programmatic manner, as its behavior may change in future releases. This was tested to function in R2017b.

Matlab simple loop for different function variables

I wrote a simple MatLab script to evaluate forward, backward and central difference approximations of first and second derivatives for a spesific function
(y = x^3-5x)
at two different x values
(x=0.5 and x = 1.5)
and for 7 different step sizes h and compare the relative errors of the approximations to the analytical derivatives.
However, i need to enter x and h values manually every time. Question is, how do I create a loop for 7 different h values and 2 different x values and get all the results as a matrix?
clc
clear all
close all
h = 0.00001;
x1 = 0.5;
y = #(x) x.^3 - 5*x;
dy = #(x) 3*x.^2 - 5;
ddy = #(x) 6*x;
d1 = dy(x1);
d2 = ddy(x1);
%Forward Differencing
f1 = (y(x1+h) - y(x1))/h;
f2 = (y(x1+2*h) - 2*y(x1+h) + y(x1))/(h.^2);
%Central Differencing
c1 = (y(x1+h)-y(x1-h))/(2*h);
c2 = (y(x1+h)-2*y(x1)+y(x1-h))/(h.^2);
% Backward Differencing
b1 = (y(x1) - y(x1-h))/h;
b2 = (y(x1)-2*y(x1-h)+y(x1-2*h))/(h.^2);
% Relative Errors
ForwardError1 = (f1 - dy(x1))/dy(x1);
ForwardError2 = (f2 - ddy(x1))/ddy(x1);
CentralError1 = (c1 - dy(x1))/dy(x1);
CentralError2 = (c2 - ddy(x1))/ddy(x1);
BackwardError1 = (b1 - dy(x1))/dy(x1);
BackwardError2 = (b2 - ddy(x1))/ddy(x1);
You don't need a loop. You can use meshgrid to create all combinations of your arguments (x and h in your case) and use these as inputs to your functions.
To get combinations of x = [0.5, 1.5] and h=0.00001:0.00001:0.00007 (I assume since you did not specify h values in the question), you would do:
[x, h] = meshgrid([0.5, 1.5], 0.00001:0.00001:0.00007);
y = #(x) x.^3 - 5*x;
f1 = (y(x1+h) - y(x1))./h;
Here x,h are matrices of size 7x2, and so is the result f1. Note that / was changed to ./ as h is a matrix and we want per-element operations.

How to write/code several functions as one

I am trying to write a line composed of two segments as a single equation in :
y = m1*x + c1 , for x<=x1
y = m2*x + c2 , for x>=x1
My questions are:
How can I write the function of this combined line as a single equation?
How can I write multiple functions (valid in separate regions of a linear parameter space) as a single equation?
Please explain both how to express this mathematically and how to program this in general and in Matlab specifically.
You can write this equation as a single line by using the Heaviside step function, https://en.wikipedia.org/wiki/Heaviside_step_function.
Combining two functions into one:
In fact, what you are trying to do is
f(x) = a(x) (for x < x1)
f(x) = q (for x = x1), where q = a(x1) = b(x1)
f(x) = b(x) (for x > x1)
The (half-maximum) Heaviside function is defined as
H(x) = 0 (for x < 0)
H(x) = 0.5 (for x = 0)
H(x) = 1 (for x > 0)
Hence, your function will be
f(x) = H(x1-x) * a(c) + H(x-x1) * b(x)
and, therefore,
f(x) = H(x1-x) * (m1*x+c1) + H(x-x1) * (m2x+c2)
If you want to implement this, note that many programming languages will allow you to write something like
f(x) = (x<x1)?a(x):b(x)
which means if x<x1, then return value a(x), else return b(x), or in your case:
f(x) = (x<x1)?(m1*x+c1):(m2x+c2)
Matlab implementation:
In Matlab, you can write simple functions such as
a = #(x) m1.*x+c1,
b = #(x) m2.*x+c2,
assuming that you have previously defined m1, m2, and c1, c2.
There are several ways to using/implementing the Heaviside function
If you have the Symbolic Math Toolbox for Matlab, you can directly use heaviside() as a function.
#AndrasDeak (see comments below) pointed out that you can write your own half-maximum Heaviside function H in Matlab by entering
iif = #(varargin) varargin{2 * find([varargin{1:2:end}], 1, 'first')}();
H = #(x) iif(x<0,0,x>0,1,true,0.5);
If you want a continuous function that approximates the Heaviside function, you can use a logistic function H defined as
H = #(x) 1./(1+exp(-100.*x));
Independently of your implementation of the Heaviside function H, you can, create a one-liner in the following way (I am using x1=0 for simplicity) :
a = #(x) 2.*x + 3;
b = #(x) -1.5.*x + 3;
Which allows you to write your original function as a one-liner:
f = #(x) H(-x).*a(x) + H(x).*b(x);
You can then plot this function, for example from -10 to 10 by writing plot(-10:10, f(-10:10)) you will get the plot below.
Generalization:
Imagine you have
f(x) = a(x) (for x < x1)
f(x) = q (for x = x1), where q = a(x1) = b(x1)
f(x) = b(x) (for x1 < x < x2)
f(x) = r (for x = x2), where r = b(x2) = c(x2)
f(x) = c(x) (for x2 < x < x3)
f(x) = s (for x = x2), where s = c(x3) = d(x3)
f(x) = d(x) (for x3 < x)
By multiplying Heaviside functions, you can now determine zones where specific functions will be computed.
f(x) = H(x1-x)*a(c) + H(x-x1)*H(x2-x)*b(x) + H(x-x2)*H(x3-x)*c(x) + H(x-x3)*d(x)
PS: just realized that one of the comments above talks about the Heaviside function, too. Kudos to #AndrasDeak .

How to implement a soft-margin SVM model using Matlab's quadprog?

Suppose we are given a training dataset {yᵢ, xᵢ}, for i = 1, ..., n, where yᵢ can either be -1 or 1 and xᵢ can be e.g. a 2D or 3D point.
In general, when the input points are linearly separable, the SVM model can be defined as follows
min 1/2*||w||²
w,b
subject to the constraints (for i = 1, ..., n)
yᵢ*(w*xᵢ - b) >= 1
This is often called the hard-margin SVM model, which is thus a constrained minimization problem, where the unknowns are w and b. We can also omit 1/2 in the function to be minimized, given it's just a constant.
Now, the documentation about Matlab's quadprog states
x = quadprog(H, f, A, b) minimizes 1/2*x'*H*x + f'*x subject to the restrictions A*x ≤ b. A is a matrix of doubles, and b is a vector of doubles.
We can implement the hard-margin SVM model using quadprog function, to get the weight vector w, as follows
H becomes an identity matrix.
f' becomes a zeros matrix.
A is the left-hand side of the constraints
b is equal to -1 because the original constraint had >= 1, it becomes <= -1 when we multiply with -1 on both sides.
Now, I am trying to implement a soft-margin SVM model. The minimization equation here is
min (1/2)*||w||² + C*(∑ ζᵢ)
w,b
subject to the constraints (for i = 1, ..., n)
yᵢ*(w*xᵢ - b) >= 1 - ζᵢ
such that ζᵢ >= 0, where ∑ is the summation symbol, ζᵢ = max(0, 1 - yᵢ*(w*xᵢ - b)) and C is a hyper-parameter.
How can this optimization problem be solved using the Matlab's quadprog function? It's not clear to me how the equation should be mapped to the parameters of the quadprog function.
The "primal" form of the soft-margin SVM model (i.e. the definition above) can be converted to a "dual" form. I did that, and I am able to get the Lagrange variable values (in the dual form). However, I would like to know if I can use quadprog to solve directly the primal form without needing to convert it to the dual form.
I don't see how it can be a problem. Let z be our vector of (2n + 1) variables:
z = (w, eps, b)
Then, H becomes diagonal matrix with first n values on the diagonal equal to 1 and the last n + 1 set to zero:
H = diag([ones(1, n), zeros(1, n + 1)])
Vector f can be expressed as:
f = [zeros(1, n), C * ones(1, n), 0]'
First set of constrains becomes:
Aineq = [A1, eye(n), zeros(n, 1)]
bineq = ones(n, 1)
where A1 is a the same matrix as in primal form.
Second set of constraints becomes lower bounds:
lb = (inf(n, 1), zeros(n, 1), inf(n, 1))
Then you can call MATLAB:
z = quadprog(H, f, Aineq, bineq, [], [], lb);
P.S. I can be mistaken in some small details, but the general idea is right.
I wanted to clarify #vharavy answer because you could get lost while trying to deduce what 'n' means in his code. Here is my version according to his answer and SVM wikipedia article. I assume we have a file named "test.dat" which holds coordinates of test points and their class membership in the last column.
Example content of "test.dat" with 3D points:
-3,-3,-2,-1
-1,3,2,1
5,4,1,1
1,1,1,1
-2,5,4,1
6,0,1,1
-5,-5,-3,-1
0,-6,1,-1
-7,-2,-2,-1
Here is the code:
data = readtable("test.dat");
tableSize = size(data);
numOfPoints = tableSize(1);
dimension = tableSize(2) - 1;
PointsCoords = data(:, 1:dimension);
PointsSide = data.(dimension+1);
C = 0.5; %can be changed
n = dimension;
m = numOfPoints; %can be also interpretet as number of constraints
%z = [w, eps, b]; number of variables in 'z' is equal to n + m + 1
H = diag([ones(1, n), zeros(1, m + 1)]);
f = [zeros(1, n), C * ones(1, m), 0];
Aineq = [-diag(PointsSide)*table2array(PointsCoords), -eye(m), PointsSide];
bineq = -ones(m, 1);
lb = [-inf(1, n), zeros(1, m), -inf];
z = quadprog(H, f, Aineq, bineq, [], [], lb);
If let z = (w; w0; eps)T be a the long vector with n+1+m elements.(m the number of points)
Then,
H= diag([ones(1,n),zeros(1,m+1)]).
f = [zeros(1; n + 1); ones(1;m)]
The inequality constraints can be specified as :
A = -diag(y)[X; ones(m; 1); zeroes(m;m)] -[zeros(m,n+1),eye(m)],
where X is the n x m input matrix in the primal form.Out of the 2 parts for A, the first part is for w0 and the second part is for eps.
b = ones(m,1)
The equality constraints :
Aeq = zeros(1,n+1 +m)
beq = 0
Bounds:
lb = [-inf*ones(n+1,1); zeros(m,1)]
ub = [inf*ones(n+1+m,1)]
Now, z=quadprog(H,f,A,b,Aeq,beq,lb,ub)
Complete code. The idea is the same as above.
n = size(X,1);
m = size(X,2);
H = diag([ones(1, m), zeros(1, n + 1)]);
f = [zeros(1,m+1) c*ones(1,n)]';
p = diag(Y) * X;
A = -[p Y eye(n)];
B = -ones(n,1);
lb = [-inf * ones(m+1,1) ;zeros(n,1)];
z = quadprog(H,f,A,B,[],[],lb);
w = z(1:m,:);
b = z(m+1:m+1,:);
eps = z(m+2:m+n+1,:);