I am trying to use solve() to solve a system of equations of the following form
eq1=a1x+a2y;
eq2=b1x+b2y;
where a1 = .05 for values of x<5, .1 for values of 5
Is there a way to solve for this using solve? As in sol = solve(eq1,eq2);
I'm not sure what you're trying to do here. Can you please post a real example (with numbers) and what you would like the output to be?
I think you're trying to solve linear simultaeneous equations. Assuming that is what you are trying to do:
I would suggest multiplying all of your equations by 20, so that your minimum quanta size of 0.05 becomes 1.00. Your problem then becomes the solution of linear equations for integer values.
Note that if the system is fully constrained (that is, if there are n independent constraints on the n equations you want to solve) then there will only be one solution and it may not necessarily be an integer solution. For example the system:
1 = 2a + 4b
3 = a + b
has the solution a = 5.5, b = -2.5. No other solution is possible.
For under-constrained systems, i.e.
0 = 3x + y
x > 0
Then there will be an infinite number of solutions, some of which may have both x and y being integer values. (Or there may be no integer solutions at all.)
Okay let me give you a quick rundown.
if you want to solve an equation or a system of equations and conditions then you need to define them as such, so let me explain.
so by example
clear all; %just to be safe
syms x y b
a=0.5;
somevalue=1;
someothervalue=3;
eq1= a*x+a*y == somevalue; %this is your first equation
eq2= b*x+b*y == someothervalue; %this is your 2nd equation
cond1= x<5; %this is a condition which matlab sees as an "equation"
eqs=[eq1,eq2,cond1]; %these are the equations and conditions you want to solve for, use this for solve
eqs=[eq1,eq2]; %use this for vpasolve and set your condition in range
vars=[x,y,b]; %these are the variable you want to solve for
range = [-Inf 5; NaN NaN; NaN NaN]; %NaN means you set no range
%you can use solve or vpasolve, second one being numeric, which is the one you'll probably want
n=5;
sol=zeros(n,numel(vars));
for i = 1:n
temp1 = vpasolve(eqs, vars, range, 'random', true);
temp = vpasolve(eqs, vars, 'random', true);
sol(i,1) = temp.x;
sol(i,2) = temp.y;
sol(i,3) = temp.b;
end
sol
Now when I run this myself I can't get the range to properly work for some reason, still trying to figure that out. When you don't set a range it works just fine, if you can use the solve function then there also isn't a problem.
In theory the range function should work fine like this so it might be a bug on my end.
If you use solve you have some nice options where you can use assume to set extra conditions that are a bit more advanced, like only checking for real solutions or only integers, etc.
Related
I have some code which uses sparse indexing (and there's no way that I can get around that). I run this in a function, and use it for two problems, where the sizes of all the variables involved do not change. However, for one problem, the sparse indexing part takes 5 seconds, and for the other, takes 25 seconds.
I checked the size of every variable involved, and they are the same for both problems. I also checked that xv is a full matrix for both problem types.
So, anyone else ever run into something weird like this? Any ideas as to why this would happen? Mainly I am trying to make the code more efficient, and while 5 seconds is ok for my particular application, 25 seconds (especially when I can't explain it) is very bad.
Edit: Here is a link to a photo that profiles this weird behavior. The runtime values were recorded on the third run to ensure that the size of X is also not changing. And I did check that xv is a dense (not sparse) matrix both times.
https://www.dropbox.com/s/i41j6afanzbjdyg/weird_bcd_thing.png?dl=0
Thanks so much for any help!
Code below (runs in a for loop). If I use ptype = 1, then it's 5 seconds, ptype = 3 is 25 seconds.
clvec = cliques{k};
xcurr = full(X(clvec));
xv = reshape(xcurr - Z(offset_index(k) + 1 : offset_index(k) + ncl^2),ncl,ncl);
%these two functions both take a dense symmetric matrix and return a dense symmetric matrix, and in both cases the size is the same for a given k.
if ptype == 1
xv = proj_PSD(xv,0,0);
elseif ptype == 3
xv = proj_Schoenberg(xv,0);
end
Xd = vec(xv) - xcurr;
%THIS IS THE WEIRD LINE
tic
X(clvec) = xv;
toc;
In the 'WEIRD LINE' : X(clvec) = xv;
You are using a random access to a sparse matrix.
This access in a sparse matrix is not constant and depends on its data. The time is may depend on the matrix values and the indices you are trying to access.
This is not the case in regular matrix, where you usually get a stable access time, and faster.
In order to assure a stable constant access try to change the implementation based on your specific matrix usage, try to avoid values assign by random access.
See next code for as a reference:
X = sparse(randi(100,50,1),randi(100,50,1),randn(1),100,100);
for i=1:10000
rand_inds{i} = randperm(10000,100);
end
for i=1:100
ti = tic;
X(rand_inds{i}) = 3;
to_X(i) = toc(ti);
end
Xf = full(X);
for i=1:100
ti = tic;
Xf(rand_inds{i}) = 3;
to_Xf(i) = toc(ti);
end
figure;plot(to_X);hold on;plot(to_Xf,'r');
I solved my problem! I'm posting the answer because I think it's interesting.
One thing I didn't mention in the question is that the loop goes from k = 1 to k = L, and for ptype = 3, we add one more step, and that's assigning all the diagonal indices to 0:
X(diag_index) = 0
where diag_index is computed ahead of time.
The problem is, instead of just assigning the values to 0, MATLAB will automatically discard these indices, and the next loop, when accessing diagonal indices, it has to re-allocate for X. So, I changed that line to
X(diag_index) = eps;
and now they both run equally fast! (It's not the best solution, since that's going to be a source of error later, but there's no more mystery!)
The answer is never what you think it would be...
I wanted to solve the following equation in MATLAB R2013a using the Symbolic Math Toolbox.
(y/x)-(((1+r)^n)-1)/r=0 where y,x and n>3 are given and r is the dependent variable
I tried myself & coded as follows:
f=solve('(y/x)-(((1+r)^n)-1)/r','r')
but as the solution for r is not exact i.e. it is converging on successive iterations hence MATLAB is giving a warning output with the message
Warning: Explicit solution could not be found.
f =
[ empty sym ]
How do I code this?
There are an infinite number of solutions to this for an unspecified value of n > 3 and unknown r. I hope that it's pretty clear why – it's effectively asking for a greater and greater number of roots of (1+r)^n. You can find solutions for fixed values of n, however. Note that as n becomes larger there are more and more solutions and of course some of them are complex. I'm going to assume that you're only interested in real values of r. You can use solve and symbolic math for n = 4, n = 5, and n = 6 (for n = 6, the solution may not be in a convenient form):
y = 441361;
x = 66990;
n = 5;
syms r;
rsol = solve(y/x-((1+r)^n-1)/r==0,r,'IgnoreAnalyticConstraints',true)
double(rsol)
However, the question is "do you need all the solutions or just a particular solution for a given value of n"? If you just need a particular solution, you shouldn't be using symbolic math at all as it's slower and has practical issues like the ones you're experiencing. You can instead just use a numerical approach to find a zero of the equation that is near a specified initial guess. fzero is the standard function for solving this sort of problem in a single variable:
y = 441361;
x = 66990;
n = 5;
f = #(r)y/x-((1+r).^n-1)./r;
r0 = 1;
rsol = fzero(f,r0)
You'll see that the value returned is the same as one of the solutions from the symbolic solution above. If you adjust the initial guess r0 (say r0 = -3), it will return the other solution. When using numeric approaches in cases when there are multiple solutions, if you want specific solutions you'll need to know about the behavior of your function and you'll need to add some clever extra code to choose initial guesses.
I think you forgot to define n as well.
f=solve('(y/x)-(((1+r)^n)-1)/r=0','n-3>0','r','n')
Should solve your problem :)
I'm trying to implement the Jacobi iteration in MATLAB but am unable to get it to converge. I have looked online and elsewhere for working code for comparison but am unable to find any that is something similar to my code and still works. Here is what I have:
function x = Jacobi(A,b,tol,maxiter)
n = size(A,1);
xp = zeros(n,1);
x = zeros(n,1);
k=0; % number of steps
while(k<=maxiter)
k=k+1;
for i=1:n
xp(i) = 1/A(i,i)*(b(i) - A(i,1:i-1)*x(1:i-1) - A(i,i+1:n)*x(i+1:n));
end
err = norm(A*xp-b);
if(err<tol)
x=xp;
break;
end
x=xp;
end
This just blows up no matter what A and b I use. It's probably a small error I'm overlooking but I would be very grateful if anyone could explain what's wrong because this should be correct but is not so in practice.
Your code is correct. The reason why it may not seem to work is because you are specifying systems that may not converge when you are using Jacobi iterations.
To be specific (thanks to #Saraubh), this method will converge if your matrix A is strictly diagonally dominant. In other words, for each row i in your matrix, the absolute summation of all of the columns j at row i without the diagonal coefficient at i must be less than the diagonal itself. In other words:
However, there are some systems that will converge with Jacobi, even if this condition isn't satisfied, but you should use this as a general rule before trying to use Jacobi for your system. It's actually more stable if you use Gauss-Seidel. The only difference is that you are re-using the solution of x and feeding it into the other variables as you progress down the rows. To make this Gauss-Seidel, all you have to do is change one character within your for loop. Change it from this:
xp(i) = 1/A(i,i)*(b(i) - A(i,1:i-1)*x(1:i-1) - A(i,i+1:n)*x(i+1:n));
To this:
xp(i) = 1/A(i,i)*(b(i) - A(i,1:i-1)*xp(1:i-1) - A(i,i+1:n)*x(i+1:n));
**HERE**
Here are two examples that I will show you:
Where we specify a system that does not converge by Jacobi, but there is a solution. This system is not diagonally dominant.
Where we specify a system that does converge by Jacobi. Specifically, this system is diagonally dominant.
Example #1
A = [1 2 2 3; -1 4 2 7; 3 1 6 0; 1 0 3 4];
b = [0;1;-1;2];
x = Jacobi(A, b, 0.001, 40)
xtrue = A \ b
x =
1.0e+09 *
4.1567
0.8382
1.2380
1.0983
xtrue =
-0.1979
-0.7187
0.0521
0.5104
Now, if I used the Gauss-Seidel solution, this is what I get:
x =
-0.1988
-0.7190
0.0526
0.5103
Woah! It converged for Gauss-Seidel and not Jacobi, even though the system isn't diagonally dominant, I may have an explanation for that, and I'll provide later.
Example #2
A = [10 -1 2 0; -1 -11 -1 3; 2 -1 10 -1; 0 3 -1 8];
b = [6;25;-11;15];
x = Jacobi(A, b, 0.001, 40);
xtrue = A \ b
x =
0.6729
-1.5936
-1.1612
2.3275
xtrue =
0.6729
-1.5936
-1.1612
2.3274
This is what I get with Gauss-Seidel:
x =
0.6729
-1.5936
-1.1612
2.3274
This certainly converged for both, and the system is diagonally dominant.
As such, there is nothing wrong with your code. You are just specifying a system that can't be solved using Jacobi. It's better to use Gauss-Seidel for iterative methods that revolve around this kind of solving. The reason why is because you are immediately using information from the current iteration and spreading this to the rest of the variables. Jacobi does not do this, which is the reason why it diverges more quickly. For Jacobi, you can see that Example #1 failed to converge, while Example #2 did. Gauss-Seidel converged for both. In fact, when they both converge, they're quite close to the true solution.
Again, you need to make sure that your systems are diagonally dominant so you are guaranteed to have convergence. Not enforcing this rule... well... you'll be taking a risk as it may or may not converge.
Good luck!
Though this does not point out the problem in your code, I believe that you are looking for the Numerical Methods: Jacobi File Exchange Submission.
%JACOBI Jacobi iteration for solving a linear system.
% Sample call
% [X,dX] = jacobi(A,B,P,delta,max1)
% [X,dX,Z] = jacobi(A,B,P,delta,max1)
It seems to do exactly what you describe.
As others have pointed out that not all systems are convergent using Jacobi method, but they do not point out why? Actually only a small sub-set of systems converge with Jacobi method.
The convergence criteria is that the "sum of all the coefficients (non-diagonal) in a row" must be lesser than the "coefficient at the diagonal position in that row". This criteria must be satisfied by all the rows. You can read more at: Jacobi Method Convergence
Before you decide to use Jacobi method, you must see whether this criteria is satisfied by the numerical method or not. The Gauss-Seidel method has a slightly more relaxed convergence criteria which allows you to use it for most of the Finite Difference type numerical methods.
this is likely a few lines of code but I cannot figure it out...
I need to perform a convolution operation of experimental data with an analytical function which is singular at the beginning of the integration range. So if I use "conv" it won't work...
I have two experimental vectors, phi(time) and time
then want to calculate T(t)
T = \int_{0}^{t}\phi \left ( t-\tau \right )\frac{\textup{d}\tau}{\tau ^{1/2}}
So the the singularity at tau = 0 makes "conv" not work. I've been fiddling with anonymous functions and using quadgk to handle the singularity and the like, but can't make anything work. I would have bet anything that this is a solved problem but can't find anything like it. Any help is very much appreciated.
EDIT: solved it this way:
function T = TCalc(time, power)
warning off MATLAB:quadgk:NonFiniteValue %suppress warning at the zero point
T=zeros(size(time));
for par = 1:numel(time)
T(par) = s1(time(par));
end
function y = r1(t)
y = interp1q(time,power,t');%notice that t is transposed! to make interp1q work.
y = y';
end
function y = s1(tfin)
y = quadgk(#(t) (r1(tfin-t))./t.^(0.5),0,tfin,'RelTol',1.e-2);
end
end
I guess, the inelegant trick here is to make Matlab think the experimental data is an analytical function by passing through interp1, and using quadgk to tolerate a singularity at the limit of integration. About one second for 1000-point vectors. Ignoring or setting the tau = 0 point to a small value doesn't work, it still perceives a singularity and the result is wrong.
I have a matrix of numbers for one of the variables in an fsolve equation so when I run matlab I am hoping to get back a matrix but instead get a scalar. I even tried a for loop but this gave me an error about size so that is not the solution. I am including the code to get some feedback as to what i am doing wrong.
z=0.1;
bubba =[1 1.5 2];
bubba = bubba';
joe = 0:0.1:1.5;
joe = repmat(joe,3,1);
bubba = repmat(bubba,1,length(joe));
for x=1:1:16
eqn0 = #(psi0) (joe.-bubba.*(sqrt((psi0+z))));
result0(x) = fsolve(eqn0,0.1,options);
end
note I need the joe variable later for plotting so I clipped that part of the code.
Based on your earlier comments, let me take a shot at a solution... still not sure this is what you want:
bubba =[1 1.5 2];
joe = 0:0.1:1.5;
for xi = 1:numel(joe)
for xj = 1:numel(bubba)
eqn0 = #(psi0) (joe(xi).-bubba(xj).*(sqrt((psi0+z))));
result(xi,xj) = fsolve(eqn0,0.1,options);
end
end
It is pedestrian; but is it what you want? I can't access matlab right now, otherwise I might come up with something more efficient.
To elaborate on my comment:
psi0 is the independent variable in your solver. You set the dimension of it to [1 1] when you use a scalar as the second argument of fsolve(eqn0, 0.1, options); - this tells Matlab to optimize the scalar psi0, starting at a value of 0.1. The result will be a scalar - the value that minimizes the function
0.1 * sqrt(psi0 + 0.1)
since you had set z=0.1
You should get a value of -0.1 returned for every iteration of your loop, since you never changed anything. There is not enough information right now to figure out which factor you would like to be a matrix - especially since your expression for eqn0 involves a matrix multiplication, it's hard to know what you expect the dimensionality of the result to be.
I hope that you will use this initial answer as a springboard to modify your question so it can be answered properly!?