I encountered some problems while trying to solve an integration equations using MapleSoft.There are 4 functions that are important. Here is my code defining the functions and trying to solve the problem:
"T is the starting point of the problem where it's given."
{T := proc (t) options operator, arrow; sqrt(t)/(sqrt(t)+sqrt(1-t))^2 end proc;}
"Now I solved for the inverse of function T."
V := proc (t) options operator, arrow;([solve(t = T(y), y, useassumptions)], [0 <= t and t <= 1]) end proc; '
"Only the first solution to the above is the correct inverse as we can see from the plot below."
sol := [allvalues(V(t))]; plot([t, T(t), op(1, sol), op(2, sol)], t = 0 .. 1, legend = [typeset("Curve: ", "t"), typeset("Curve: ", "T(t)"), typeset("Curve: ", "V(t)"), typeset("Curve: ", "V2(t)")]);
"Now I define the first solution as my inverse function called V1."
V1 := proc (t) options operator, arrow; evalf(op(1, sol)) end proc
"As the problem required, I have to find the derivative of V1. I call it dV."
dV := proc (t) options operator, arrow; diff(V1(t), t) end proc
"Then define a new function called F"
F := proc (t) options operator, arrow; -10*ln(1-t*(1-exp(-1))) end proc
"With V1(t), F(t), dV(t) defined, we define a new function U."
U := proc (t,lambda) options operator, arrow; piecewise(t <= .17215, min(IVF(V1(t)), max(0, 12-(1/4)/(lambda^2*dV(t)^2))), .17215 <= t, min(IVF(V1(t)), max(0, 12-(1/4)*.7865291304*lambda^-2))) end proc;
"Next I will be trying to find the value of lambda, such that the"
solve(int(U(t,lambda)*dV(t),t=0..1)= R,lambda)
"where the R will be a real number, let's say 2.93 for now."
I think the code works fine all the way till the last step where I had to solve the integration. I couldn't figure out why.
I was trying to progress further, solving the U, i.e U(t) will be 0 if t<=0.17215 and 12-(1/4)/(lambda^2*dV(t)^2)<=0 or t>=0.17215 and 12-(1/4)*0.7865291304*lambda^-2<=0 and so on so forth. But had problem solving the inequality. For example, solve(12-1/4*lambda^-2*dV(t)^-2<=0,t). The programme runs indefinitely.
Appreciate your input!
I'm guessing that by IVF(V1(t)) you really meant F(V(t)) .
It seemed to me that computation of your dV(t) (and perhaps V(t) sometimes) for very small t might exhibit some numerical difficulty.
And I was worried that using a narrower range of integration like, say, t=1.0e-2 .. 1.0, might mess with some significant contribution to the integral from that portion.
So below I've constructed V and dV so that they raised Digits (only) for greater working precision on (only) their own body of calculations.
And I've switched it from symbolic integration to numeric/float integration. And I've added the epsilon option for that, in case you need to control the accuracy tolerance more finely.
Some of these details help with the speed issues you mentioned above. And some of those details slow the computation down a bit, while perhaps giving a greater sense of robustness of it.
The plotting command calls below are just there for illustration. Comment them out if you please.
I used Maple 2018.0 for these. If you have difficulties then please report your particular version used.
restart;
T:=sqrt(x)/(sqrt(x)+sqrt(1-x))^2:
Vexpr:=solve(t=T,x,explicit)[1]:
Vexpr:=simplify(combine(Vexpr)) assuming t>0, t<1:
The procedure for computing V is constructed next. It's constructed in this subtle way for two reasons:
1) It internally raises working precision Digits to avoid round-off error.
2) It creates (and throws away) an empty list []. The effect of this is that it will not run under fast hardware-precision evalhf mode. This is key later on, during the numeric integration.
V:=subs(__dummy=Vexpr,
proc(t)
if not type(t,numeric) then
return 'procname'(t);
end if;
[];
Digits:=100;
evalf(__dummy);
end proc):
V(0.25);
0.2037579200498004992002294012453548811286405373\
653346413644953624868320875151070347969077227713469370
V(1e-9);
1.0000000040000000119998606410199120814521886485524\
-18
22617659574502917213370846924673012122642160567565 10
Let's plot T and V,
plot([T, V(x)], x=0..1);
Now let's create a procedure for the derivative of V, using the same technique so that it too raises Digits (only internal to itself) and will not run under evalhf.
dV:=subs(__dummy=diff(Vexpr,t),
proc(t)
if not type(t,numeric) then
return 'procname'(t);
end if;
[];
Digits:=100;
evalf(__dummy);
end proc):
Note that calling dV(t) for unknown symbol t makes it return unevaluated. This is convenient later on.
dV(t);
dV(t)
dV(0.25);
2.44017580084567947538393626436824494366329948208270464559139762\
2347525580165201957710520046760103982
dV(1e-15);
-5.1961525404198771358909147606209930290335590838862019038834313\
73611362758951860627325613490378754702
evalhf(dV(1e-15)); # I want this to error-out.
Error, unable to evaluate expression to hardware floats: []
This is your F.
F:=t->-10*ln(1-t*(1-exp(-1))):
Now create the procedure U. This too returns unevaluated when either of its argument is not an actual number. Note that lambda is its second parameter.
U:=proc(t,lambda)
if not ( type(t,numeric) and
type(lambda,numeric) ) then
return 'procname'(args);
end if;
piecewise(t <= .17215,
min(F(V(t)), max(0, 12-(1/4)/(lambda^2*dV(t)^2))),
t >= .17215,
min(F(V(t)), max(0, 12-(1/4)*.7865291304*lambda^(-2))));
end proc:
Let's try a particular value of t=0.2 and lambda=2.5.
evalf(U(0.2, 2.5));
.6774805135
Let's plot it. This takes a little while. Note that it doesn't seem to blow up for small t.
plot3d([Re,Im](U(t,lambda)),
t=0.0001 .. 1.0, lambda=-2.0 .. 2.0,
color=[blue,red]);
Let's also plot dV. This takes a while, since dV raises Digits. Note that it appears accurate (not blowing up) for small t.
plot(dV, 0.0 .. 1.0, color=[blue,red], view=-1..4);
Now let's construct a procedure H which computes the integral numerically.
Note that lambda is it's first parameter, which it passes as the second argument to U. This relates to your followup Comment.
The second parameter of H is passed to evalf(Int(...)) to specify its accuracy tolerance.
Note that the range of integration is 0.001 to 1.0 (for t). You can try a lower end-point closer to 0.0 but it will take even longer for compute (and may not succeed).
There is a complicated interplay between the lower end-point of numeric integration, and accuracy tolerance eps, and the numeric behavior for U and V and dV for very small t.
(The working precision Digits is set to 15 inside H. That's just to allow the method _d01ajc to be used. It's still the case that V and dV will raise working precision for their own computations, at each numeric invocation of the integrand. Also, I'm using unapply and a forced choice of numeric integration method as a tricky way to prevent evalf(Int(...)) from wasting a lot of time poking at the integrand to find singularities. You don't need to completely understand all these details. I'm just explaining that I had reasons for this complicated set-up.)
H:=proc(lambda,eps)
local res,t;
Digits:=15;
res:=evalf(Int(unapply(U(t,lambda)*dV(t),t),
1e-3..1,
epsilon=eps, method=_d01ajc) - R);
if type(res,numeric) then
res;
else
Float(undefined);
end if;
end proc:
Let's try calling H for a specific R. Note that it's not fast.
R:=2.93;
R := 2.93
H(0.1,1e-3);
-2.93
H(0.2,1e-5);
0.97247264305333
Let's plot H for a fixed integration tolerance. This takes quite a while.
[edited] I originally plotted t->H(t,1e-3) here. But your followup Comment showed a misunderstanding in the purpose of the first parameter of that operator. The t in t->H(t,1e-3) is just a dummy name and DOES NOT relate to the t parameter of V and dV, and the second parameter of U, and the integration varaible. What matters is that this dummy is passed as the first argument to H, which in turn passes it as the second argument to U, which is used for lambda. Since there was confusion earlier, I'll use the dummy name LAMBDA now.
plot(LAMBDA->H(LAMBDA,1e-3), 0.13 .. 0.17 , adaptive=false, numpoints=15);
Now let's try and find the value of that root (intercept).
[edited] Here too I was earlier using the dummy name t for the first argument of H. It's just a dummy name and does not relate to the t parameter of V and dV, and the second parameter of U, and the variable of integration. So I'll change it below to LAMBDA to lessen confusion.
This is not fast. I'm minimizing the absolute value because numeric accuracy issues make this problematic for numeric root-finder fsolve.
Osol:=Optimization:-Minimize('abs(H(LAMBDA,1e-3))', LAMBDA=0.15..0.17);
[ -8 ]
Osol := [1.43561000000000 10 , [LAMBDA = 0.157846355888300]]
We can pick off the numeric value of lambda (which "solved" the integration).
rhs(Osol[2,1]);
0.157846355888300
If we call H using this value then we'll get a residual (similar to the first entry in Osol, but without absolute value being taken).
H(rhs(Osol[2,1]), 1e-3);
-8
-1.435610 10
Now you have the tools to try and obtain the root more accurately. To do so you may experiment with:
tighter (smaller) eps the tolerance of numeric integration.
A lower end-point of the integration closer to 0.0
Even higher Digits forced within the procedures V and dV.
That will require patience, since the computations take a while, and since the numeric integration can fail (taking forever) when those three aspects are not working properly together.
I've I edit the body of procedure H and change the integration range to instead be 1e-4 .. 1.0 then I get the following result (specifying 1e-5 for eps in the call to H).
Osol:=Optimization:-Minimize('abs(H(LAMBDA,1e-5))', LAMBDA=0.15..0.17);
[ -7 ]
Osol := [1.31500690000000 10 , [LAMBDA = 0.157842787382700]]
So it's plausible that this approximate root lambda is accurate to perhaps 4 or 5 decimal places.
Good luck.
Related
Using Mathematica I need to evaluate the integral of a function. Since it is taking the program too much to compute it, would it be possible to use parallel computation to shorten the time needed? If so, how can I do it?
I uploaded a picture of the integrand function:
I need to integrate it with respect to (x3, y3, x, y) all of them ranging in a certain interval (x3 and y3 from 0 to 1) (x and y from 0 to 100). The parameters (a,b,c...,o) are preventing the NIntegrate function to work. Any suggestions?
If you evaluate this
expr=E^((-(x-y)^4-(x3-y3)^4)/10^4)*
(f x+e x^2+(m+n x)x3-f y-e y^2-(m+n y)y3)*
((378(x-y)^2(f x+e x^2+(m+n x)x3-f y-e y^2-(m+n y)y3))/
(Pi(1/40+Sqrt[((x-y)^2+(x3-y3)^2)^3]))+
(378(x-y)(x3-y3)(h x+g x^2+(o+p x)x3-h y-g y^2-(o+p y)y3))/
(Pi(1/40+Sqrt[((x-y)^2+(x3-y3)^2)^3])))+
(h x+g x^2+(o+p x)x3-h y-g y^2-(o +p y) y3)*
((378(x-y)(x3-y3)(f x+e x^2+(m+n x)x3-f y-e y^2-(m+n y)y3))/
(Pi(1/40+Sqrt[((x-y)^2+(x3-y3)^2)^3]))+
(378 (x3 - y3)^2 (h x + g x^2 + (o + p x)x3-h y-g y^2-(o+p y)y3))/
(Pi(1/40+Sqrt[((x-y)^2+(x3-y3)^2)^3])));
list=List ## Expand[expr]
then you will get a list of 484 expressions, each very similar in form to this
(378*f*h*x^3*x3)/(Pi*(1/40+Sqrt[(x^2+x3^2-2*x*y+y^2-2*x3*y3+y3^2)^3]))
Notice that you can then use NIntegrate in this way
f*h*NIntegrate[(378*x^3*x3)/(Pi*(1/40+Sqrt[(x^2+x3^2-2*x*y+y^2-2*x3*y3+y3^2)^3])),
{x,0,100},{y,0,100},{x3,0,1},{y3,0,1}]
but it gives warnings and errors about the convergence and accuracy, almost certainly due to your fractional powers in the denominator.
If you can find a way to pull out the scalar multipliers which are independent of x,y,x3,y3 and then perform that integration without warnings and errors and get an accurate result which isn't infinity then you could perhaps perform these integrals in parallel and total the results.
Some of the integrands are scalar multiples of others and if you combine similar integrands then you can reduce this down to 300 unique integrands.
I doubt this is going to lead to an acceptable solution for you.
Please check all this very carefully to make certain that no mistakes have been made.
EDIT
Since the variables that are independent of the integration appear to be easily separated from the dependent variables in the problem posed above, I think this will allow parallel NIntegrate
independentvars[z_] := (z/(z//.{e->1, f->1, g->1, h->1, m->1, n->1, o->1, p->1}))*
NIntegrate[(z//.{e->1, f->1, g->1, h->1, m->1, n->1, o->1, p->1}),
{x, 0, 100}, {y, 0, 100}, {x3, 0, 1}, {y3, 0, 1}]
Total[ParallelMap[independentvars, list]]
As I mentioned previously, the fractional powers in the denominator result in a flood of warnings and errors about convergence failing.
You can test this with the following much simpler example
expr = f x + f g x3 + o^2 x x3;
list = List ## Expand[expr];
Total[ParallelMap[independentvars, list]]
which instantly returns
500000. f + 5000. f g + 250000. o^2
This is a very primitive method of pulling independent symbolic variables outside an NIntegrate. This gives absolutely no warning if one of the integrands is not in a form where this primitive attempt at extraction is not appropriate or fails.
There may be a far better method that someone else has written out there somewhere. If someone could show a far better method of doing this then I would appreciate it.
It might be nice if Wolfram would consider incorporating something like this into NIntegrate itself.
I'd like to write a Mathematica function that takes an expression as argument, takes the derivative of that expression, and then does something to the expression. So (as a toy example) I'd like to write
F[f_] = D[f, x] * 2
so that
F[x^2] = 4x
Instead, I get
F[x^2] = 0
Can someone point me to the relevant docs? I spent some time poking around the Mathematica reference, but didn't find anything helpful.
You've used assignment = when you mean to use delayed assignment :=. When you evaluate F[f_]=D[f,x]*2 using (non-delayed) assignment, Mathematica looks at D[f,x] and sees that f (an unassigned symbol) does not depend on x; hence, its derivative is 0. Thus, F[f_]=0 for any arguments to F, which is what it returns later.
If you want F to be evaluated only after you have specified what f_ should be, you need to use delayed assignment by replacing = with :=.
I'm all new to Matlab and I'm supposed to use this function to find all 3 zero spots.
f.m (my file where the function can be found)
function fval = f(x)
% FVAL = F(X), compute the value of a test function in x
fval = exp(-x) - exp(-2*x) + 0.05*x - 0.25;
So obviously I write "type f" to read my function but then I try to do like fzero ('f', 0) and I get the ans 0.4347 and I assume that's 1 of my 3 zero spots but how to find the other 2?
From fzero documentation
x = fzero(fun,x0) tries to find a zero of fun near x0, if x0 is a scalar. fun is a function handle. The value x returned by fzero is near a point where fun changes sign, or NaN if the search fails. In this case, the search terminates when the search interval is expanded until an Inf, NaN, or complex value is found.
So it can't find all zeros by itself, only one! Which one depends on your inputted x0.
Here's an example of how to find some more zeros, if you know the interval. However it just repeatedly calls fzero for different points in the interval (and then still can miss a zero if your discretization is to coarse), a more clever technique will obviously be faster:
http://www.mathworks.nl/support/solutions/en/data/1-19BT9/index.html?product=ML&solution=1-19BT9
As you can see in the documentation and the example above, the proper way for calling fzero is with a function handle (#fun), so in your case:
zero1 = fzero(#f, 0);
From this info you can also see that the actual roots are at 0.434738, 1.47755 and 4.84368. So if you call fzero with 0.4, 1.5 and 4.8 you probably get those values out of it (convergence of fzero depends on which algorithm it uses and what function you feed it).
Just to complement Gunther Struyf's answer: there's a nice function on the file exchange by Stephen Morris called FindRealRoots. This function finds an approximation to all roots of any function on any interval.
It works by approximating the function with a Chebyshev polynomial, and then compute the roots of that polynomial. This obviously only works well with continuous, smooth and otherwise well-behaved functions, but the function you give seems to have those qualities.
You would use this something like so:
%# find approximate roots
R = FindRealRoots(#f, -1, 10, 100);
%# refine all roots thus found
for ii = 1:numel(R)
R(ii) = fzero(#f, R(ii)); end
I am trying to solve this problem :
(Write a program to compute the real roots of a quadratic equation (ax2 + bx + c = 0). The roots can be calculated using the following formulae:
x1 = (-b + sqrt(b2 - 4ac))/2a
and
x2 = (-b - sqrt(b2 - 4ac))/2a
I wrote the following code, but its not correct:
program week7_lab2_a1;
var a,b,c,i:integer;
x,x1,x2:real;
begin
write('Enter the value of a :');
readln(a);
write('Enter the value of b :');
readln(b);
write('Enter the value of c :');
readln(c);
if (sqr(b)-4*a*c)>=0 then
begin
if ((a>0) and (b>0)) then
begin
x1:=(-1*b+sqrt(sqr(b)-4*a*c))/2*a;
x2:=(-1*b-sqrt(sqr(b)-4*a*c))/2*a;
writeln('x1=',x1:0:2);
writeln('x2=',x2:0:2);
end
else
if ((a=0) and (b=0)) then
write('The is no solution')
else
if ((a=0) and (b<>0)) then
begin
x:=-1*c/b;
write('The only root :',x:0:2);
end;
end
else
if (sqr(b)-4*a*c)<0 then
write('The is no real root');
readln;
end.
do you know why?
and taking a=-6,b=7,c=8 .. can you desk-check it after writing the pesudocode?
You have an operator precedence error here:
x1:=(-1*b+sqrt(sqr(b)-4*a*c))/2*a;
x2:=(-1*b-sqrt(sqr(b)-4*a*c))/2*a;
See at the end, the 2 * a doesn't do what you think it does. It does divide the expression by 2, but then multiplies it by a, because of precedence rules. This is what you want:
x1:=(-1*b+sqrt(sqr(b)-4*a*c))/(2*a);
x2:=(-1*b-sqrt(sqr(b)-4*a*c))/(2*a);
In fact, this is because the expression is evaluated left-to-right wrt brackets and that multiplication and division have the same priority. So basically, once it's divided by 2, it says "I'm done with division, I will multiply what I have now with a as told".
As it doesn't really seem clear from the formula you were given, this is the quadratic formula:
As you can see you need to divide by 2a, so you must use brackets here to make it work properly, just as the correct text-only expression for this equation is x = (-b +- sqrt(b^2 - 4ac)) / (2a).
Otherwise the code looks fine, if somewhat convoluted (for instance, you could discard cases where (a = 0) and (b = 0) right after input, which would simplify the logic a bit later on). Did you really mean to exclude negative coefficients though, or just zero coefficients? You should check that.
Also be careful with floating-point equality comparison - it works fine with 0, but will usually not work with most constants, so use an epsilon instead if you need to check if one value is equal to another (like such: abs(a - b) < 1e-6)
Completely agree with what Thomas said in his answer. Just want to add some optimization marks:
You check the discriminant value in if-statement, and then use it again:
if (sqr(b)-4*a*c)>=0 then
...
x1:=(-1*b+sqrt(sqr(b)-4*a*c))/2*a;
x2:=(-1*b-sqrt(sqr(b)-4*a*c))/2*a;
This not quite efficient - instead of evaluating discriminant value at once you compute it multiple times. You should first compute discriminant value and store it into some variable:
D := sqr(b)-4*a*c;
and after that you can use your evaluated value in all expressions, like this:
if (D >= 0) then
...
x1:=(-b+sqrt(D)/(2*a);
x2:=(-b-sqrt(D)/(2*a);
and so on.
Also, I wouldn't write -1*b... Instead of this just use -b or 0-b in worst case, but not multiplication. Multiplication here is not needed.
EDIT:
One more note:
Your code:
if (sqr(b)-4*a*c)>=0 then
begin
...
end
else
if (sqr(b)-4*a*c)<0 then
write('The is no real root');
You here double check the if-condition. I simplify this:
if (a) then
begin ... end
else
if (not a)
...
Where you check for not a (in your code it corresponds to (sqr(b)-4*a*c)<0) - in this case condition can be only false (for a) and there is no need to double check it. You should just throw it out.
I have bumped into this problem several times on the type of input data declarations mathematica understands for functions.
It Seems Mathematica understands the following types declarations:
_Integer,
_List,
_?MatrixQ,
_?VectorQ
However: _Real,_Complex declarations for instance cause the function sometimes not to compute. Any idea why?
What's the general rule here?
When you do something like f[x_]:=Sin[x], what you are doing is defining a pattern replacement rule. If you instead say f[x_smth]:=5 (if you try both, do Clear[f] before the second example), you are really saying "wherever you see f[x], check if the head of x is smth and, if it is, replace by 5". Try, for instance,
Clear[f]
f[x_smth]:=5
f[5]
f[smth[5]]
So, to answer your question, the rule is that in f[x_hd]:=1;, hd can be anything and is matched to the head of x.
One can also have more complicated definitions, such as f[x_] := Sin[x] /; x > 12, which will match if x>12 (of course this can be made arbitrarily complicated).
Edit: I forgot about the Real part. You can certainly define Clear[f];f[x_Real]=Sin[x] and it works for eg f[12.]. But you have to keep in mind that, while Head[12.] is Real, Head[12] is Integer, so that your definition won't match.
Just a quick note since no one else has mentioned it. You can pattern match for multiple Heads - and this is quicker than using the conditional matching of ? or /;.
f[x:(_Integer|_Real)] := True (* function definition goes here *)
For simple functions acting on Real or Integer arguments, it runs in about 75% of the time as the similar definition
g[x_] /; Element[x, Reals] := True (* function definition goes here *)
(which as WReach pointed out, runs in 75% of the time
as g[x_?(Element[#, Reals]&)] := True).
The advantage of the latter form is that it works with Symbolic constants such as Pi - although if you want a purely numeric function, this can be fixed in the former form with the use of N.
The most likely problem is the input your using to test the the functions. For instance,
f[x_Complex]:= Conjugate[x]
f[x + I y]
f[3 + I 4]
returns
f[x + I y]
3 - I 4
The reason the second one works while the first one doesn't is revealed when looking at their FullForms
x + I y // FullForm == Plus[x, Times[ Complex[0,1], y]]
3 + I 4 // FullForm == Complex[3,4]
Internally, Mathematica transforms 3 + I 4 into a Complex object because each of the terms is numeric, but x + I y does not get the same treatment as x and y are Symbols. Similarly, if we define
g[x_Real] := -x
and using them
g[ 5 ] == g[ 5 ]
g[ 5. ] == -5.
The key here is that 5 is an Integer which is not recognized as a subset of Real, but by adding the decimal point it becomes Real.
As acl pointed out, the pattern _Something means match to anything with Head === Something, and both the _Real and _Complex cases are very restrictive in what is given those Heads.