How to write a `lhs()` or `rhs()` function for symbolic expressions on Matlab - matlab

I have a symbolic expression in MATLAB with a == operator that I can use in solve(). What I want is to separate out the left hand side and the right hand side of the expression into two separate symbolic expressions.
For example:
expr = sym('[1-x^2==2*y; 1+x^2==x+y]');
side1 = lhs(expr); % returns side1 = [1-x^2; 1+x^2];
of course my expressions are far more complicated, and it is always vector or matrix form.
Workaround 1
I can use the MuPAD built-in function lhs() but I wanted to know if it possible to do this using only MATLAB functions and I want to make it work for vectors of expressions and not just one value.
This is what I have so far that works as expected. Maybe the result filling can be vectorized somehow by using : but I have not manage to get it working.
function [ r ] = lhs( expr )
%LHS Returns the left hand side an expression
% LHS(sym('[1-x^2==2*y'; 1+x^2==x+y]')) = [1-x^2; 1+x^2]
cmd = #(e)['lhs(',char(e),')'];
[m,n] = size(expr);
r = sym(zeros(m,n));
for i=1:m
for j=1:n
r(i,j) = evalin(symengine, cmd(expr(i,j)));
end
end
end

Starting R2017a, use "lhs" and "rhs" as
syms x
expr = [1-x^2==2*y; 1+x^2==x+y];
lhsExpr = lhs(expr)
lhsExpr =
1 - x^2
x^2 + 1
rhsExpr = rhs(expr)
rhsExpr =
2*y
x + y

expr = sym('[1-x^2==2*y; 1+x^2==x+y]');
lr = children(expr);
lr{1}
ans =
[ 1 - x^2, 2*y]
Note that this is more robust than EitanT's string manipulation for a simple reason: Your left- and right-hand sides may contain equals-signs themselves.

I'm thinking regular expressions, so here's my shot at this.
Let's say you have a symbolic expression expr, for instance:
expr = sym('[1-x^2==2*y; 1+x^2==x+y]')
Since it cannot be assumed to be a scalar expression, the first step would be splitting it into sub-elements, and converting each one to a string, like so:
C = arrayfun(#(n)char(expr(n)), 1:numel(expr), 'Uniform', false)
(I'm not using a simple char(expr) conversion because it adds the matrix([[...]]) syntax).
Now we use a regular expression search-and-replace to extract the LHS:
C = arrayfun(#(n)char(expr(n)), 1:numel(expr), 'Uniform', false)
C = regexprep(C, '([^><=]*)(?:[><=]*)(.*)', '$1') %// $1 for lhs, $2 for rhs
And then concatenate the elements back into a string and convert it into a symbolic expression:
str = sprintf('%s,', C{:})
result = reshape(sym(str(1:end - 1)), size(expr))
Voila.
Here are copy-paste friendly lhs and rhs functions:
function y = lhs(x)
C = arrayfun(#(n)char(x(n)), 1:numel(x), 'Uniform', false);
C = regexprep(C, '([^><=]*)(?:[><=]*)(.*)', '$1');
str = sprintf('%s,', C{:});
y = reshape(sym(str(1:end - 1)), size(x));
function y = rhs(x)
C = arrayfun(#(n)char(x(n)), 1:numel(x), 'Uniform', false);
C = regexprep(C, '([^><=]*)(?:[><=]*)(.*)', '$2');
str = sprintf('%s,', C{:});
y = reshape(sym(str(1:end - 1)), size(x));
Note that the only difference between lhs and rhs are the replaced tokens in regexprep.
Using $1 extracts the left-hand side, and using $2 extracts the right-hand side.

Related

Evaluate integral limits using the antiderivatives expression, with a calculator

THE QUESTION IS
Is there a compact way to evaluate an antidevivative expression: x**3 / 2 | x = a; x = b
When we have an indefinite integral of the form:
# Pseudocode as I cannot write it in math mode
expr = x**2; a = 1; b = 5;
F = integral(expr, x); # integral of expr
Definite_integral = F.subs(x, b) - F.subs(x, a);
We can also do this by just using the built-in integrate function
# Pseudocode
expr = x**2;
a = 1; b = 5;
Definite_integra = integrate(expr, x, a, b) # integrate expr from a to b
However, the problem is that I start with an expression for the antiderivative
x**3 / 3
Ideally, I'd just want to express it with itegration brackets, example:
I don't want to repeat myself and write the expression twice and I don't really want to declare the expression as a (unnecessary; only used unce) function just to express it as: f(b) - f(a) or more in line with Ti Nspire notation: f(x)|x=b - f(x)|x=a
You can define bracket using a little helper function.
The screenshot below is from the Notes area.

MATLAB Equation as User Input to work with

I'm trying to write a simple script that request a equation as input and I like to calculate with this function more than once without always requesting user input.
My current script defined f as function handle and executed the function 2 times, so I'm always asking for a new equation, which is not desirable.
f = #(x) input('f(x) = ');
a = f(2); % requests user input
b = f(3); % requests user input again
And it should look more like this (not working).
func = input('f(x) = ');
f = #(x) func;
a = f(2);
b = f(3);
And here without user input to get an idea what I try to achieve.
f = #(x) x^2;
a = f(2);
b = f(3);
I think I found a solution with Symbolic Math Toolbox, but I do not have this addon, so I cannot use/test it.
Is there another solution?
There's no need for the Symbolic Mathematics Toolbox here. You can still use input. Bear in mind that the default method of input is to directly take the input and assign it as a variable where the input is assumed to be syntactically correct according to MATLAB rules. That's not what you want. You'll want to take the input as a string by using the 's' option as the second parameter then use str2func to convert the string into an anonymous function:
func = input('f(x) = ', 's');
f = str2func(['#(x) ' func]);
a = f(2);
b = f(3);
Take note that I had to concatenate the #(x) anonymous function string with the inputted function you provided with input.
Example Run
Let's say I want to create a function that squares every element in the input:
>> func = input('f(x) = ', 's');
f(x) = x.^2
>> f = str2func(['#(x) ' func])
f =
#(x)x.^2
>> a = f(2)
a =
4
>> b = f(3)
b =
9
Take special note that I assumed the function will element-wise square each elements in the input. The . operator in front of the exponentiation operator (i.e. ^) is very important.

Integrate function in MATLAB

I am new to Matlab. I would like to integrate a function. I try int() and integrate() but they all cause problems to me - not enough parameters or other different errors, I have tried many combinations with documentation. My current code is the following, I would like to be able to pass numbers p and q to res and obtain a numerical result:
syms x;
w = 1;
hbar = 1.054571800*10^(-34);
k = (w/(pi*hbar))^(1/4);
e = #(q) (w*q/hbar)^(1/2);
waveF = #(q) k*exp(-feval(e,q)*feval(e,q)*1/2.0)*1.0/1;
func = #(p,q) waveF(q-x/2)*waveF(q+x/2)*exp(1i*p*x/(hbar));
res = #(p,q) int(func(p,q), x = -Inf..Inf);
Currently " x = " is indicated as en error although it seems ok according to the documentation.
Thanks.
You are using anonymous functions in concert with the Symbolic Toolbox and have mistakenly used the MuPAD version of int, which is actually generating the error, when you wanted the Symbolic int.
While mixing anonymous functions with Symbolic calls is not illegal, I think you would be better served by sticking to one paradigm of computation at a time:
Purely Symbolic version using Symbolic functions:
syms x p q e(q) waveF(q) func(p,q) res(p,q);
w = sym(1);
hbar = sym('1.054571800E-34');
k = (w/(pi*hbar))^(1/4);
e(q) = sqrt(w*q/hbar);
waveF(q) = k*exp(-e(q)^2/2);
func(p,q) = waveF(q-x/2)*waveF(q+x/2)*exp(1i*p*x/(hbar));
res(p,q) = int(func(p,q),x,-Inf,Inf);
I wrapped the value of hbar in quotes to force the use of the supplied value and not the nearest rational representation that would've been coerced during computation.
Purely numeric version using anonymous functions and the numeric integral function:
w = 1;
hbar = 1.054571800E-34;
k = (w/(pi*hbar)).^(1/4);
e = #(q) sqrt(w*q/hbar);
waveF = #(q) k*exp(-e(q).^2/2);
func = #(p,q,x) waveF(q-x/2).*waveF(q+x/2).*exp(1i*p*x/hbar);
res = #(p,q) integral(#(x) func(p,q,x),-Inf,Inf);
Both of these version generate NaN when res is evaluated, but that's probably a shortcoming of the integrand. However, the functional forms and ideas behind the above scripts won't change with different integrands.

Factor symbolic expression involving exp()

I have a symbolic function exp(a+b), and would like to factor out A=exp(a) to produce exp(a+b) = A*exp(b), but I cannot figure out how to do this in MATLAB. Below is my attempt:
syms a b A
X = exp(a+b);
Y = subs(X,exp(a),A) % = A*exp(b)
however, Y = exp(a+b). For some reason, MATLAB cannot determine:
exp(a+b) = exp(a) * exp(b) = A*exp(b).
Any help is greatly appreciated.
First, expand the expression so that the exponents are separated then do the substitution. By default, when writing out an expression for the first time (before running it through any functions), MATLAB will try and simplify your expression and so exp(a)*exp(b) can be much better expressed using exp(a+b). This is why your substitution had no effect. However, if you explicitly want to replace a part of the expression that is encompassed by an exponent with a base, expand the function first, then do your substitution:
>> syms a b A;
>> X = exp(a+b);
>> Xexpand = expand(X)
Xexpand =
exp(a)*exp(b)
>> Y = subs(Xexpand, exp(a), A)
Y =
A*exp(b)

How to vectorize a piecewise periodic function in MATLAB?

I've noticed that matlab builtin functions can handle either scalar or vector parameters. Example:
sin(pi/2)
ans =
1
sin([0:pi/5:pi])
ans =
0 0.5878 0.9511 0.9511 0.5878 0.0000
If I write my own function, for example, a piecewise periodic function:
function v = foo(t)
t = mod( t, 2 ) ;
if ( t < 0.1 )
v = 0 ;
elseif ( t < 0.2 )
v = 10 * t - 1 ;
else
v = 1 ;
end
I can call this on individual values:
[foo(0.1) foo(0.15) foo(0.2)]
ans =
0 0.5000 1.0000
however, if the input for the function is a vector, it is not auto-vectorized like the builtin function:
foo([0.1:0.05:0.2])
ans =
1
Is there a syntax that can be used in the definition of the function that indicates that if a vector is provided, a vector should be produced? Or do builtin functions like sin, cos, ... check for the types of their input, and if the input is a vector produce the same result?
You need to change your syntax slightly to be able to handle data of any size. I typically use logical filters to vectorise if-statements, as you're trying to do:
function v = foo(t)
v = zeros(size(t));
t = mod( t, 2 ) ;
filt1 = t<0.1;
filt2 = ~filt1 & t<0.2;
filt3 = ~filt1 & ~filt2;
v(filt1) = 0;
v(filt2) = 10*t(filt2)-1;
v(filt3) = 1;
In this code, we've got three logical filters. The first picks out all elements such that t<0.1. The second picks out all of the elements such that t<0.2 that weren't in the first filter. The final filter gets everything else.
We then use this to set the vector v. We set every element of v that matches the first filter to 0. We set everything in v which matches the second filter to 10*t-1. We set every element of v which matches the third filter to 1.
For a more comprehensive coverage of vectorisation, check the MATLAB help page on it.
A simple approach that minimizes the number of operations is:
function v = foo(t)
t = mod(t, 2);
v = ones(size(t)) .* (t > 0.1);
v(t < 0.2) = 10*t(t < 0.2) - 1;
end
If the vectors are large, it might be faster to do ind = t < 0.2, and use that in the last line. That way you only search through the array once. Also, the multiplication might be substituted by an extra line with logical indices.
I repeatedly hit the same problem, thus I was looking for a more generic solution and came up with this:
%your function definition
c={#(t)(mod(t,2))<0.1,0,...
#(t)(mod(t,2))<0.2,#(t)(10 * t - 1),...
true,1};
%call pw which returns the function
foo=pw(c{:});
%example evaluation
foo([0.1:0.05:0.2])
Now the code for pw
function f=pw(varargin)
for ip=1:numel(varargin)
switch class(varargin{ip})
case {'double','logical'}
varargin{ip}=#(x)(repmat(varargin{ip},size(x)));
case 'function_handle'
%do nothing
otherwise
error('wrong input class')
end
end
c=struct('cnd',varargin(1:2:end),'fcn',varargin(2:2:end));
f=#(x)pweval(x,c);
end
function y=pweval(x,p)
todo=true(size(x));
y=x.*0;
for segment=1:numel(p)
mask=todo;
mask(mask)=logical(p(segment).cnd(x(mask)));
y(mask)=p(segment).fcn(x(mask));
todo(mask)=false;
end
assert(~any(todo));
end