I have to solve in MATLAB a linear system of equations A*x=B where A is symmetric and its elements depend on the difference of the indices: Aij=f(i-j).
I use iterative solvers because the size of A is say 40000x40000. The iterative solvers require to determine the product A*x where x is the test solution. The evaluation of this product turns out to be a convolution and therefore can be done dy means of fast fourier transforms (cputime ~ Nlog(N) instead of N^2). I have the following questions to this problem:
is this convolution circular? Because if it is circular I think that I have to use a specific indexing for the new matrices to take the fft. Is that right?
I find difficult to program the routine for the fft because I cannot understand the indexing I should use. Is there any ready routine which I can use to evaluate by fft directly the product A*x and not the convolution? Actually, the matrix A is constructed of 3x3 blocks and is symmetric. A ready routine for the product A*x would be the best solution for me.
In case that there is no ready routine, could you give me an idea by example how I could construct this routine to evaluate a matrix-vector product by fft?
Thank you in advance,
Panos
Very good and interesting question! :)
For certain special matrix structures, the Ax = b problem can be solved very quickly.
Circulant matrices.
Matrices corresponding to cyclic convolution Ax = h*x (* - is convolution symbol) are diagonalized in
the Fourier domain, and can be solved by:
x = ifft(fft(b)./fft(h));
Triangular and banded.
Triangular matrices and diagonally-dominant banded matrices are solved
efficiently by sparse LU factorization:
[L,U] = lu(sparse(A)); x = U\(L\b);
Poisson problem.
If A is a finite difference approximation of the Laplacian, the problem is efficiently solved by multigrid methods (e.g., web search for "matlab multigrid").
Interesting question!
The convolution is not circular in your case, unless you impose additional conditions. For example, A(1,3) should equal A(2,1), etc.
You could do it with conv (retaining only the non-zero-padded part with option valid), which probably is also N*log(N). For example, let
A = [a b c d
e a b c
f e a b
g f e a];
Then A*x is the same as
conv(fliplr([g f e a b c d]),x,'valid').'
Or more generally, A*x is the same as
conv(fliplr([A(end,1:end-1) A(1,:)]),x,'valid').'
I'd like to add some comments on Pio_Koon's answer.
First of all, I wouldn't advise to follow the suggestion for triangular and banded matrices. The time taken by a call to Matlab's lu() procedure on a large sparse matrix massively overshadows any benefits gained by solving the linear system as x=U\(L\b).
Second, in the Poisson problem you end up with a circulant matrix, therefore you can solve it using the FFT as described. In this specific case, your convolution mask h is a Laplacian, i.e., h=[0 -0.25 0; -0.25 1 -0.25; 0 -0.25 0].
Related
I have a matrix that is a function of some parameter A=A(x). I would like to find the points x where this matrix becomes singular. Example (I have a large matrix though):
syms x
A=[x sin(x); cos(x^2) 2.5];
So far I have been symbolically computing the determinant of the matrix and then used fzero or newtzero to find the roots of that characteristic equation. I.e.
detA = det(A);
fzero(matlabFunction(detA),startingGuess)
Then I found this: How to find out if a matrix is singular?, where it is advocated to not use the determinant under any circumstances.
Indeed the symbolic determinant calculation is terribly slow. However I tried to use rank(A) instead as suggested in the link and it does not seem to work for symbolic matrices.
Is there any way to implement the suggestions in the link for finding the roots of a characteristic equation of a matrix that is given symbolically?
A possible approach would be the following: a square matrix A is singular if and only if the homogeneous linear (with respect to the vector y) system A*y = 0 has nontrivial solutions y <> 0 (which is equivalent to det(A) = 0 and rank(A) = 0 among others. So a more or less standard, as I recall from the past, technique to compute such points x is to solve the nonlinear system
A(x)*y = 0 (1)
||y|| = 1 (2)
This way you can compute a point x* and a vector y* such that A(x*) is singular and y* is an eigenvector corresponding to the zero eigenvalue of A(x*).
If I remember correctly, you can also solve the somewhat easier system
A(x)*y = 0 (1)
<y,c> = 1 (2a)
where c is "almost" any nonzero random vector (normalize it to 1 to avoid numerical problems).
As a matter of fact there is an enormous bibliography on the subject - you can look for saddle-node bifurcation computations (in case A(x) is the Jacobian of a vector field), or for "distance to instability".
From a discussion with Ander Biguri it seems that the determinant is actually a perfectly fine method of approaching this problem. The problem seems to be to solve the final equation in a stable manner, which would be a different question.
I have a question about solving linear equation Ax=b, in which x is unknown, A is square matrix NxN and non-singular matrix.
The vector x can be solved by
x=inv(A)*b
or
x=A\b
In Matlab, the ‘\’ command invokes an algorithm which depends upon the structure of the matrix A and includes checks (small overhead) on properties of A. Hence, It highly depends on A structure. However, A structure is unknown (i.e random matrix). I want to measure complexity of above equation. Hence, to fairly comparison, I need to fixed the method which I used. In this case, I choose Gaussian Elimination (GE) with complexity O(N^3) My question is how can I choose/fix the method (i.e. GE) to solve above equation?
One way would be to compute the LU factorisation (assuming A is not symmetric)
[L,U] = lu(A)
where L is a permutation of a lower-triangular matrix with unit diagonal and U is upper triangular. This is equivalent to the Gaussian elimination.
Then, when you solve Ax = b, you actually perform first Ly = b and then Ux = y.
The important thing is that solving these linear system is essentially O(n^2), while computing the factorisation is O(n^3). So if n is big, you can just measure the time taken to compute the LU factorisation.
For random matrices, you can see the complexity of the LU factorization like that
nn = round(logspace(2, 4, 20)) ;
time = zeros(size(nn)) ;
for i = 1:numel(nn)
A = rand(nn(i),nn(i)) ;
tic() ; [L,U] = lu(A) ;
time(i) = toc() ;
end
loglog(nn,time) ;
(change the "4" to something bigger or smaller, depending on you pc).
On my laptop, I have this result
where the slop of 3 (hence, the O(n^3) complexity) is fairly clear.
I wanna solve #n linear equations AX=bi(for #n b's) in Matlab which b changes in a loop and A is constant.
One way which is fast, is to compute the inverse of A before the loop and in the loop body just get X from inv(A)*b, but because the matrix A is singular, I get an awful answer!
Of course, the numerical solution A/b gives a good answer, but the point is that it takes a long time to compute #n different X's in #n loops.
What I want is a solution which can be both accurate and fast.
I actually think this is a good question, typos and issues of matrix singularity aside. There are a few good ways to handle this, and Tim Davis' factorize submission on MATLAB Central covers all the angles.
However, just for reference, let's do it on our own in native MATLAB, starting with the case where A is square. First, there are the two methods you suggested (inv and \,mldivide):
% inv, slow and inacurate
xinvsol = inv(A)*b;
norm(A*xinvsol - b ,'fro')
% mldivide, faster and accurate
xref = A\b;
norm(A*xref - b ,'fro')
But if like you said A does not change, just factorize A and solve for new b! Say A is symmetric positive definite:
L = chol(A,'lower'); % Cholesky factorization
% mldivide, much faster (not counting the chol factorization) and most accurate
xcholbs= L'\(L\b); %'
norm(A*xcholbs - b ,'fro')
% linsolve, fastest (omits checks for matrix configuration) and most accurate
sol1 = linsolve(L, b, struct('LT',true));
xcholsolv = linsolve(L, sol1, struct('LT',true,'TRANSA',true));
norm(A*xcholsolv - b ,'fro')
If A is not symmetric positive definite, then you'd use LU decomposition for a square matrix or QR otherwise. Again, you can do it all yourself, or you can just use Tim Davis' awesome factorize functions.
I am wondering how to draw samples in matlab, where I have precision matrix and mean as the input argument.
I know mvnrnd is a typical way to do so, but it requires the covariance matrix (i.e inverse of precision)) as the argument.
I only have precision matrix, and due to the computational issue, I can't invert my precision matrix, since it will take too long (my dimension is about 2000*2000)
Good question. Note that you can generate samples from a multivariant normal distribution using samples from the standard normal distribution by way of the procedure described in the relevant Wikipedia article.
Basically, this boils down to evaluating A*z + mu where z is a vector of independent random variables sampled from the standard normal distribution, mu is a vector of means, and A*A' = Sigma is the covariance matrix. Since you have the inverse of the latter quantity, i.e. inv(Sigma), you can probably do a Cholesky decomposition (see chol) to determine the inverse of A. You then need to evaluate A * z. If you only know inv(A) this can still be done without performing a matrix inverse by instead solving a linear system (e.g. via the backslash operator).
The Cholesky decomposition might still be problematic for you, but I hope this helps.
If you want to sample from N(μ,Q-1) and only Q is available, you can take the Cholesky factorization of Q, L, such that LLT=Q. Next take the inverse of LT, L-T, and sample Z from a standard normal distribution N(0, I).
Considering that L-T is an upper triangular dxd matrix and Z is a d-dimensional column vector,
μ + L-TZ will be distributed as N(μ, Q-1).
If you wish to avoid taking the inverse of L, you can instead solve the triangular system of equations LTv=Z by back substitution. μ+v will then be distributed as N(μ, Q-1).
Some illustrative matlab code:
% make a 2x2 covariance matrix and a mean vector
covm = [3 0.4*(sqrt(3*7)); 0.4*(sqrt(3*7)) 7];
mu = [100; 2];
% Get the precision matrix
Q = inv(covm);
%take the Cholesky decomposition of Q (chol in matlab already returns the upper triangular factor)
L = chol(Q);
%draw 2000 samples from a standard bivariate normal distribution
Z = normrnd(0,1, [2, 2000]);
%solve the system and add the mean
X = repmat(mu, 1, 2000)+L\Z;
%check the result
mean(X')
var(X')
corrcoef(X')
% compare to the sampling from the covariance matrix
Y=mvnrnd(mu,covm, 2000)';
mean(Y')
var(Y')
corrcoef(Y')
scatter(X(1,:), X(2,:),'b')
hold on
scatter(Y(1,:), Y(2,:), 'r')
For more efficiency, I guess you can search for some package that efficiently solves triangular systems.
I compute the multinomial Gaussian density for some huge number of times in a project where I update the covariance matrix by rank-1. Instead of computing the covariance from scratch, I used the cholupdate function to add a new sample to the covariance and remove a new sample to the covariance. By this way, the update is told to be in $O(n^2)$ as opposed to $O(n^3)$ Cholesky factorization of the covariance matrix.
persistent R
if (initialize) % or isempty(R)
% compute covariance V
R = chol(V);
else
R = cholupdate(R,xAdded);
detVar = prod(diag(R))^2;
Rt = R';
coeff = 1/sqrt((2*pi)^dimension*detVar);
y = Rt\x;
logp = log(coeff) - 1/2 * norm(y)^2;
Actually the code is quite complicated but I simplified it here. I wonder if there is a faster way to compute the inverse (the Rt\x part in the code) of an upper triangular matrix in MATLAB. Do you have any ideas to do it more efficiently in MATLAB.
Note that computing the determinant is also faster this way. So the new method will also not bad for the computation of the determinant.
The mldivide function is smart enough to check for triangular matrices, in which case it uses a forward/backward substitution method to efficiently solve the linear system:
AX=B <--> X=inv(A)*B <--> X=A\B
(compute x1, substitute it in second equation and compute x2, substitute in third ...)