I have three vectors A, B, and C. For each value in these vectors I would like to solve the equation C^x = A^x + B^x. Unfortunately this is an equation that I have found to be solvable only iteratively, so I am attempting to use MATLAB's "solve" function to find a solution for each case. My code is as follows:
exponents = zeros(100,1);
syms x
A = rand(100,1);
B = rand(100,1);
C = rand(100,1);
for i = 1:100
exponents(i) = eval(solve(C(i)^x == A(i)^x + B(i)^x));
end
Sometimes, however, the solution is unobtainable, which leads to the error message, "Warning: Explicit solution could not be found." I am okay with this, but if I run into an unsolvable equation, I would like to simply leave the "exponents(i)" unchanged for that iteration and move onto the next one, instead of having my code abruptly stop. Any suggestions?
If you put the statement that causes the occasional error inside a try/catch statement, then the error will not cause execution to stop. For example, you could try:
for i = 1:100
try
exponents(i) = eval(solve(C(i)^x == A(i)^x + B(i)^x));
catch
exponents(i) = NaN;
end;
end
There is not a direct way in MATLAB for catching warnings (at least a documented way). It is not elegant in the slightest, if not downright ugly, you can try polling the output of lastwarn.
...
exponents(i) = eval(solve(C(i)^x == A(i)^x + B(i)^x));
[~, msgid] = lastwarn;
if strcmp(msgid, YOURWARNINGID)
continue;
end
There is a similar post here, except the poster was getting an error.
Related
I am trying to make a portion of my code run faster in MatLab, and I'd like to use parfor. When I try to, I get the following error about one of my variables D_all.
"The PARFOR loop cannot run because of the way D_all is used".
Here is a sample of my code.
M = 161;
N = 24;
P = 161;
parfor n=1:M*N*P
[j,i,k] = ind2sub([N,M,P],n);
r0 = Rw(n,1:3);
R0 = repmat(r0,M*N*P,1);
delta = sqrt(dXnd(i)^2 + dZnd(k)^2);
d = R_prime - R0;
inS = Rw_prime(find(sqrt(sum(d.^2,2))<0.8*delta),:);
if isempty(inS)
D_all(j,i,k,tj) = D_all(j,i,k,tj-1);
else
y0 = r0(2);
inC = inS(find(inS(:,2)==y0),:);
dw = sqrt(sum(d(find(sqrt(sum(d.^2,2))<0.8*delta & d(:,2)==0),:).^2,2));
V_avg = sum(dw.^(-1).*inC(:,4))/sum(dw.^(-1));
D_all(j,i,k,tj) = V_avg;
end
end
I'm not very familiar with parallel computing, and I've looked at the guides online and don't really understand how to apply them to my situation. I guess I need to "slice" D_all but I don't know how to do that.
EDIT: I think I understand that the major problem is that when using D_all I have tj and tj-1.
EDIT 2: I don't show this above, it probably would have been helpful, but I defined D_all(:,:,:,1) = V_1; where V_1 corresponds to a previous time step. I tried making multiple variables V_2, V_3, etc. for each step and replacing D_all(j,i,k,tj-1) with V_1(j,i,k). This still led to the same error I am seeing with D_all.
"Valid indices for D_all are restricted for PARFOR loops"
Ok, so I've defined the function MetBisectiei which has the following code:
function [xaprox] = MetBisectiei(Fun,a,b,eps)
Fa = Fun(a);
Fb = Fun(b);
if Fa*Fb>0
xaprox = ('Error: The function has the same sign at points a and b.');
else
N=ceil((log10(b-a)-log10(eps))/log10(2));
for i = 1:n
xaprox = (a+b)/2;
Fxaprox=Fun(xaprox);
if(Fxaprox == 0)
break
end
if Fa*Fxaprox<0
b=Fxaprox;
else
a=xaprox;
Fa=Fxaprox;
end
end
end
And when I try to actually use the function to find the solution of an equation, I get the following error, which doesn't actually explain what's wrong:
Error in tema2_2 (line 8)
xaprox = MetBisectiei(f,0,1,eps);
The code to find the solution of the equation is this one:
syms x
f = x^3-7*x^2+14*x-6;
f = matlabFunction(f);
x = 0:4;
y = f(x);
plot(x,y);
eps = 10^(-5);
xaprox = MetBisectiei(f,0,1,eps);
I see few mistakes here. First you should terminate
function [xaprox] = MetBisectiei(Fun,a,b,eps)
with end, the one visible in your example just close if statement. The second problem is that n is not defined, probably you miss that matlab is case-sensitive, and N is not equal to n. So you should:
n=ceil((log10(b-a)-log10(eps))/log10(2));
If you fix this two things - your codes finish without any errors, (xaprox = 0.5210) tested on Matlab R2017b.
I want to add an While-loop to my matlab-code so that it will stop when the iteration is good enough. With some kind of tolerance, eg. 1e-6.
This is my code now. So i need to add some kind of stopping criteria, i have tried several times now but it won't work... I appreciate all of ur help!
x(1)=1;
iterations = 0;
tolerance = 1e-6;
% Here should the while be....
for i=1:N
x(i+1)=x(i);
for j=1:N
x(i+1)=F(x(i),x(i+1));
end
end
iter= iter + 1;
Well, somehow you need to compute the 'error' you are doing in each iteration. In your case it would be something like this:
iter = 0;
tolerance = 1e-6;
error=1;
x=F(x);
while(error>tolerance)
x2=x;
x=F(x);
error = x-x2;
iter= iter + 1;
end
Note how at the beginning the error is set to 1 so we make sure it goes inside the loop. We also compute the first instance of x outside the loop. F(x) will be your function to evaluate, change it for whatever you need.
Inside the loop assign the old value of x to x2, then compute the new x and finally compute the error. Here I compute the error as x-x2 but you might need to compute this error in another way.
The loop will exit whenever the error is lower than the tolerance.
Can anyone explain to me, why the following gives an error for u but nor for h
max_X = 100;
max_Y = 100;
h = ones(max_Y,max_X);
u = zeros(max_Y,max_X);
parfor l=1:max_X*max_Y
i = mod(l-1,max_X) + 1;
j = floor((l-1)/max_Y) + 1;
for k=1:9
m = i + floor((k-1)/3) - 1;
n = j + mod(k,-3) + 1;
h_average(k) = sqrt(h(i,j)*h(m,n));
u_average(k) = (u(i,j)*sqrt(h(i,j)) + u(m,n)*sqrt(h(m,n)))/(sqrt(h(i,j)) + sqrt(h(m,n)));
end
end
I can now substitute (i,j) with (l), but even if I try to calculate the related variable, let's call it p, according to (m,n), and write u(p) instead of u(m,n) it gives me an error message.
It only underlines the u(m,n), resp. u(p) but not the h(m,n).
MATLAB says:
Explanation:
For MATLAB to execute parfor loops efficiently, the amount of data sent to the MATLAB workers must be minimal. One of the ways MATLAB achieves this is by restricting the way variables can be indexed in parfor iterations. The indicated variable is indexed in a way that is incompatible with parfor.
Suggested Action
Fix the indexing. For a description of the indexing restrictions, see “Sliced Variables” in the Parallel Computing Toolbox documentation
Any idea, what's wrong here?
The problems with u and h are that they are both being sent as broadcast variables to the PARFOR loop. This is not an error - it's just a warning indicating that more data than might otherwise be necessary is being sent.
The PARFOR loop cannot run because you're indexing but not slicing u_average and h_average. It's not clear what outputs you want from this loop since you're overwriting u_average and h_average each time, therefore the PARFOR loop is pointless.
I created a function in matlab that returns a vector like
function w = W_1D(x,pos,h)
w=zeros(1,length(x));
if (h~=0)
xmpos = x-pos;
inds1 = (-h <= xmpos) & (xmpos < 0);
w(inds1) = xmpos(inds1)./h + 1;
inds2 = (0 <= xmpos) & (xmpos <= h);
w(inds2) = -xmpos(inds2)./h + 1;
else
error('h shouldn't be 0')
end
end
Thus, in the end, there is a vector w of size length(x).
Now i created a second function like
function f = W_2D(x,y,pos_1,pos_2,h)
w_x = W_1D(x,pos_1,h);
w_y = W_1D(y,pos_2,h);
f = w_x'*w_y;
end
where length(x)=length(y). Thus, the function W_2D obviously returns a matrix.
But when I now try to evaluate the integral over a rectangular domain like e.g.
V = integral2(#(x,y) W_2D(x,y,2,3,h),0,10,0,10);
matlab returns some errors:
Error using integral2Calc>integral2t/tensor (line 242)
Integrand output size does not match the input size.
Error in integral2Calc>integral2t (line 56)
[Qsub,esub] = tensor(thetaL,thetaR,phiB,phiT);
Error in integral2Calc (line 10)
[q,errbnd] = integral2t(fun,xmin,xmax,ymin,ymax,optionstruct);
Error in integral2 (line 107)
Q = integral2Calc(fun,xmin,xmax,yminfun,ymaxfun,opstruct);
I also tried to vary something in the W_2D-function: instead of f = w_x'*w_y;
I tried f = w_x.'*w_y;
or w_y = transpose(w_y); f = kron(w_x,w_y);, but there is always this error with the Integrand output size-stuff.
Can anyone explain, where my fault is?
EDIT: After Werner's hint with the keyboard debugging method, I can tell you the following.
The first step returns w_x of type <1x154 double>, w_y is <1x192 double>, x and y are both <14x14 double>. In the next step, f appears with a value of <154x192 double>. Then everything disappears, except x and y and the matlab-function integral2Calc.m appears in the editor and it jumps to the Function Call Stack integral2t/tensor and after some more steps, the error occurs here
Z = FUN(X,Y); NFE = NFE + 1;
if FIRSTFUNEVAL
if ~isfloat(Z)
error(message('MATLAB:integral2:UnsupportedClass',class(Z)));
end
% Check that FUN is properly vectorized. This is important here
% because we (otherwise) always pass in square matrices, which
% reduces the probability of the user generating an error by
% using matrix functions instead of elementwise functions.
Z1 = FUN(X(VTSTIDX),Y(VTSTIDX)); NFE = NFE + 1;
if ~isequal(size(Z),size(X)) || ~isequal(size(Z1),size(VTSTIDX))
% Example:
% integral2(#(x,y)1,0,1,0,1)
error(message('MATLAB:integral2:funSizeMismatch'));
end
Hope that information is detailed enough...I have no idea what happenes, because my example is exact as it is given on the mathworks site about integral2, isn't it?
Maybe I should precise a bit more, what I wanna do: since W_2D gives me a surface w(x,y) of a compactly supported 2-dimensional hat-function, stored in a matrix w, I want to calculate the volume between the (x,y)-plane and the surface z=w(x,y)...
EDIT2: I still do not understand how to handle the problem, that integral2 creates matrices as inputs for my W_1D-functions, which are called in W_2D and intended to have a <1xn double>-valued input and return a <1xn double> output, but at least I can simply use the following to solve the integration over the tensor product by using two one-dimensional integral-calls, that is
V = integral(#(x)integral(#(y)W_1D(y,3,h),0,10).*W_1D(x,2,h),0,10);
This first function is quite wrong. You are not indexing the array positions while you are doing w = x inside for.
Besides, if that would work, you are returning a line vector, that is, size 1xlength(x) and when you do w_x'*w_y you are doing length(x)x1 times 1xlength(y), which would give you a matrix length(x)*length(y).
Consider correcting your function:
function w = W_1D(x,pos)
w = zeros(length(x),1); % Allocate w as column vector, so that the product gives a scalar (as I suppose that it is what you want.
for ii=1:length(x) % Here, so that is indexes w and x elements as you need
w(ii)=x(ii) - pos; % I changed your code to something that makes sense, but I don't know if that is what you want to do, you have to adapt it to work correctly.
end
end
You may also want to debug your functions, consider adding keyboard before your operations and check what they are returning using dbstep. I.e:
function f = W_2D(x,y,pos_1,pos_2)
w_x = W_1D(x,pos_1);
w_y = W_1D(y,pos_2);
keyboard
f = w_x'*w_y;
end
Execution will stop at keyboard, then you can check w_x size, w_y size, and do dbstep to go after f = w_x'*w_y and see what it returned. After you finish debug, you can do dbcont so that it will continue execution.
This answer is a draft as it is quite difficult to help you with the information you have provided. But I think you can start working the things out with this. If you have more doubts feel free to ask.