I am using the matlab code from this book: http://books.google.com/books/about/Probability_Markov_chains_queues_and_sim.html?id=HdAQdzAjl60C
Here is the Code:
function [pi] = GE(Q)
A = Q';
n = size(A);
for i=1:n-1
for j=i+1:n
A(j,i) = -A(j,i)/A(i,i);
end
for j =i+1:n
for k=i+1:n
A(j,k) = A(j,k)+ A(j,i) * A(i,k);
end
end
end
x(n) = 1;
for i = n-1:-1:1
for j= i+1:n
x(i) = x(i) + A(i,j)*x(j);
end
x(i) = -x(i)/A(i,i);
end
pi = x/norm(x,1);
Is there a faster code that I am not aware of? I am calling this functions millions of times, and it takes too much time.
MATLAB has a whole set of built-in linear algebra routines - type help slash, help lu or help chol to get started with a few of the common ways to efficiently solve linear equations in MATLAB.
Under the hood these functions are generally calling optimised LAPACK/BLAS library routines, which are generally the fastest way to do linear algebra in any programming language. Compared with a "slow" language like MATLAB it would not be unexpected if they were orders of magnitude faster than an m-file implementation.
Hope this helps.
Unless you are specifically looking to implement your own, you should use Matlab's backslash operator (mldivide) or, if you want the factors, lu. Note that mldivide can do more than Gaussian elimination (e.g., it does linear least squares, when appropriate).
The algorithms used by mldivide and lu are from C and Fortran libraries, and your own implementation in Matlab will never be as fast. If, however, you are determined to use your own implementation and want it to be faster, one option is to look for ways to vectorize your implementation (maybe start here).
One other thing to note: the implementation from the question does not do any pivoting, so its numerical stability will generally be worse than an implementation that does pivoting, and it will even fail for some nonsingular matrices.
Different variants of Gaussian elimination exist, but they are all O(n3) algorithms. If any one approach is better than another depends on your particular situation and is something you would need to investigate more.
function x = naiv_gauss(A,b);
n = length(b); x = zeros(n,1);
for k=1:n-1 % forward elimination
for i=k+1:n
xmult = A(i,k)/A(k,k);
for j=k+1:n
A(i,j) = A(i,j)-xmult*A(k,j);
end
b(i) = b(i)-xmult*b(k);
end
end
% back substitution
x(n) = b(n)/A(n,n);
for i=n-1:-1:1
sum = b(i);
for j=i+1:n
sum = sum-A(i,j)*x(j);
end
x(i) = sum/A(i,i);
end
end
Let's assume Ax=d
Where A and d are known matrices.
We want to represent "A" as "LU" using "LU decomposition" function embedded in matlab thus:
LUx = d
This can be done in matlab following:
[L,U] = lu(A)
which in terms returns an upper triangular matrix in U and a permuted lower triangular matrix in L such that A = LU. Return value L is a product of lower triangular and permutation matrices. (https://www.mathworks.com/help/matlab/ref/lu.html)
Then if we assume Ly = d where y=Ux.
Since x is Unknown, thus y is unknown too, by knowing y we find x as follows:
y=L\d;
x=U\y
and the solution is stored in x.
This is the simplest way to solve system of linear equations providing that the matrices are not singular (i.e. the determinant of matrix A and d is not zero), otherwise, the quality of the solution would not be as good as expected and might yield wrong results.
if the matrices are singular thus cannot be inversed, another method should be used to solve the system of the linear equations.
For the naive approach (aka without row swapping) for an n by n matrix:
function A = naiveGauss(A)
% find's the size
n = size(A);
n = n(1);
B = zeros(n,1);
% We have 3 steps for a 4x4 matrix so we have
% n-1 steps for an nxn matrix
for k = 1 : n-1
for i = k+1 : n
% step 1: Create multiples that would make the top left 1
% printf("multi = %d / %d\n", A(i,k), A(k,k), A(i,k)/A(k,k) )
for j = k : n
A(i,j) = A(i,j) - (A(i,k)/A(k,k)) * A(k,j);
end
B(i) = B(i) - (A(i,k)/A(k,k)) * B(k);
end
end
function Sol = GaussianElimination(A,b)
[i,j] = size(A);
for j = 1:i-1
for i = j+1:i
Sol(i,j) = Sol(i,:) -( Sol(i,j)/(Sol(j,j)*Sol(j,:)));
end
end
disp(Sol);
end
I think you can use the matlab function rref:
[R,jb] = rref(A,tol)
It produces a matrix in reduced row echelon form.
In my case it wasn't the fastest solution.
The solution below was faster in my case by about 30 percent.
function C = gauss_elimination(A,B)
i = 1; % loop variable
X = [ A B ];
[ nX mX ] = size( X); % determining the size of matrix
while i <= nX % start of loop
if X(i,i) == 0 % checking if the diagonal elements are zero or not
disp('Diagonal element zero') % displaying the result if there exists zero
return
end
X = elimination(X,i,i); % proceeding forward if diagonal elements are non-zero
i = i +1;
end
C = X(:,mX);
function X = elimination(X,i,j)
% Pivoting (i,j) element of matrix X and eliminating other column
% elements to zero
[ nX mX ] = size( X);
a = X(i,j);
X(i,:) = X(i,:)/a;
for k = 1:nX % loop to find triangular form
if k == i
continue
end
X(k,:) = X(k,:) - X(i,:)*X(k,j);
end
Related
I have been using the following custom function to perform the multiplication of a vector by a matrix, in which each element of the vector multiplies a 3x3 block within a (3xN)x(3) matrix:
function [B] = BlockScalar(v,A)
N=size(v,2);
B=zeros(3*N,3);
for i=1:N
B(3*i-2:3*i,:) = v(i).*A(3*i-2:3*i,:);
end
end
Similarly, when I want to multiply a collection of 3x3 matrices by a collection of 3x3 vectors, I use the following
function [B] = BlockMatrix(A,u)
N=size(u,2);
B=zeros(N,3);
for i=1:N
B(i,:) = A(3*i-2:3*i,:)*u(:,i);
end
end
Since I call them very often, these unfortunately, slow down the running of my code significantly. I was wondering if there was a more efficient (perhaps vectorised) version of the above operations.
In both instance, you are able to do away with the for-loops (although without testing, I cannot confirm if this will necessarily speed up your computation).
For the first function, you can do it as follows:
function [B] = BlockScalar(v,A)
% We create a vector N = [1,1,1,2,2,2,3,3,3,...,N,N,N]
N=ceil((1:size(A,1))/3);
% Use N to index v, and let matlab do the expansion
B = v(N).*A;
end
For the second function, we can make a block-diagonal matrix.
function [B] = BlockMatrix(A,u)
N=size(u,2)*3;
% We use a little meshgrid+sparse magic to convert A to a block matrix
[X,Y] = meshgrid(1:N,1:3);
% Use sparse matrices to speed up multiplication and save space
B = reshape(sparse(Y+(ceil((1:N)/3)-1)*3,X,A) * (u(:)),3,size(u,2))';
end
Note that if you are able to access the individual 3x3 matrices, you can potentially make this faster/simpler by using the native blkdiag:
function [B] = BlockMatrix(a,b,c,d,...,u)
% Where A = [a;b;c;d;...];
% We make one of the input matrices sparse to make the whole block matrix sparse
% This saves memory and potentially speeds up multiplication by a lot
% For small enough values of N, however, using sparse may slow things down.
reshape(blkdiag(sparse(a),b,c,d,...) * (u(:)),3,size(u,2))';
end
Here are vectorized solutions:
function [B] = BlockScalar(v,A)
N = size(v,2);
B = reshape(reshape(A,3,N,3) .* v, 3*N, 3);
end
function [B] = BlockMatrix(A,u)
N = size(u,2);
A_r = reshape(A,3,N,3);
B = (A_r(:,:,1) .* u(1,:) + A_r(:,:,2) .* u(2,:) + A_r(:,:,3) .* u(3,:)).';
end
function [B] = BlockMatrix(A,u)
N = size(u,2);
B = sum(reshape(A,3,N,3) .* permute(u, [3 2 1]) ,3).';
end
After finding equations of motion using the Symbolic Toolbox (R2016b, Windows), I have the following form:
M(q)*qddot = b(q,qdot) + u
M and b were found using equationsToMatrix.
Now, I need to separate b into Coriolis and Potential terms such that
M(q)*qddot + C(q,qdot)*qdot + G(q) = u
It would be extremely convenient if I could apply
[C,G] = equationsToMatrix(b,qdot)
but unfortunately it will not factor out qdot when b is nonlinear. I do not care (and in fact it is necessary) that C is a function of q and qdot, even after factoring out the vector qdot. I have tried coeffs and factor without results.
Thanks.
Posting my own solution so there can be at least one answer...
This function works, but it is not heavily tested. It works exactly as I suggested in my original question. Feel free to rename it so it doesn't conflict with the MATLAB builtin.
function [A,b] = equationsToMatrix( eq, x )
%EQUATIONSTOMATRIX equationsToMatrix for nonlinear equations
% factors out the vector x from eq such that eq = Ax + b
% eq does not need to be linear in x
% eq must be a vector of equations, and x must be a vector of symbols
assert(isa(eq,'sym'), 'Equations must be symbolic')
assert(isa(x,'sym'), 'Vector x must be symbolic')
n = numel(eq);
m = numel(x);
A = repmat(sym(0),n,m);
for i = 1:n % loop through equations
[c,p] = coeffs(eq(i),x); % separate equation into coefficients and powers of x(1)...x(n)
for k = 1:numel(p) % loop through found powers/coefficients
for j = 1:m % loop through x(1)...x(n)
if has(p(k),x(j))
% transfer term c(k)*p(k) into A, factoring out x(j)
A(i,j) = A(i,j) + c(k)*p(k)/x(j);
break % move on to next term c(k+1), p(k+1)
end
end
end
end
b = simplify(eq - A*x,'ignoreanalyticconstraints',true); % makes sure to fully cancel terms
end
I am playing with image processing algorithms in MATLAB. One of the basic ones is convolving an image with a Gaussian. I ran the following test on a grayscale 800x600 image:
function [Y1, Y2] = testConvolveTime(inputImage)
[m,n] = size(inputImage);
% casting...
inputImage = cast(inputImage, 'single');
Gvec = [1 4 6 4 1]; % sigma=1;
Y1 = zeros(size(inputImage)); % modify it
Y2 = zeros(size(inputImage)); % modify it
%%%%%%%%%%%%%%%%%%% MATLAB CONV %%%%%%%%%%%%%%%%%%%%%
t1 = cputime;
for i=1:m
Y1(i,:) = conv(inputImage(i,:),Gvec,'same');
end
for j=1:n
Y1(:,j) = conv(inputImage(:,j),Gvec','same');
end
Y1 = round(Y1 / 16);
e1 = cputime - t1
%%%%%%%%%%%%%%%%%%% HAND-CODED CONV %%%%%%%%%%%%%%%%%%%%%
t2 = cputime;
for i=1:m
Y2(i,:) = myConv(inputImage(i,:),Gvec)';
end
for j=1:n
Y2(:,j) = myConv(inputImage(:,j),Gvec');
end
Y2 = round(Y2 / 16);
e2 = cputime - t2
end
Here is the code I wrote implementing convolution of 2 vectors:
% mimic MATLAB's conv(u,v,'same') function
% always returns column vec
function y = myConv(u_in, v_in)
len1 = length(u_in);
len2 = length(v_in);
if (len1 >= len2)
u = u_in;
v = v_in;
else
u = v_in;
v = u_in;
end
% from here on: v is the shorter vector (len1 >= len2)
len1 = length(u);
len2 = length(v);
maxLen = len1 + len2 - 1;
ytemp = zeros(maxLen,1);
% first part -- partial overlap
for i=1:len2-1
sum = 0;
for j=1:i
sum = sum + u(i-j+1)*v(j);
end
ytemp(i) = sum;
end
% main part -- complete overlap
for i=len2:len1
sum = 0;
for j=1:len2
sum = sum + u(i-j+1)*v(j);
end
ytemp(i) = sum;
end
% finally -- end portion
for i=len1+1:maxLen
%i-len1+1
sum = 0;
for j=i-len1+1:len2
sum = sum + u(i-j+1)*v(j);
end
ytemp(i) = sum;
end
%y = ytemp;
startIndex = round((maxLen - length(u_in))/2 + 1);
y = ytemp(startIndex:startIndex+length(u_in)-1);
% ^ note: to match MATLAB's conv(u,v,'same'), the output length must be
% that of the first argument.
end
Here are my test results:
>> [Y1, Y2] = testConvolveTime(A1);
e1 =
0.5313
e2 =
195.8906
>> norm(Y1 - Y2)
ans =
0
The norm being 0 verifies mathematical correctness. My questions are as follows:
How can my hand-coded function be >360x slower than the one that uses MATLAB's conv?
Even MATLAB's conv is still "slow" for image processing. If convolving with a Gaussian takes 0.5 of a second, what hope is there for running any image processing algorithms in real-time (e.g. at 24 FPS)? For reference my CPU is Intel N3540 # 2.16 GHz. w/ 8GB of RAM.
^ The real question: when I switch to OpenCV on C++, will operations like this become much faster?
1) conv is so much faster because it is an built-in native function, while your function is interpreted MATLAB code with nested loops.
2) Try imfilter in the Image Processing Toolbox. It may be faster than conv, and it works on uint8 arrays. Or, if you get a more recent version of MATLAB, and if you only need the Gaussian filter, try imgaussfilt.
Because (discrete) convolution is often represented via linear algebra but certainly not via for loops. In fact everytime you walk through rows or columns you should seek for ways to represent it as an algebraic operation.
The typical way is to do it via Toeplitz matrices but can be extended to way faster algorithms. And once you have the toeplitz structure then you can optimize the multiplication even further
https://en.wikipedia.org/wiki/Toeplitz_matrix#Discrete_convolution
http://www.netlib.org/utk/people/JackDongarra/etemplates/node384.html
Note that native Matlab functions can still be slow. It is not an indication of speed but maintenance level. Often you can find the algorithm used linked in the documentation and you can decide whether you should go for the custom implementation or the standard.
Why convolution in matalab is faster?
The implementation itself is very efficient.
They use fast techniques to perform multiplication and convolution.
check the BLAS, ATLAS packages if you want to see tricks to do these things very fast.
in practical (convolution in the original domain \ time or space) and (multiplication in frequency domain) are equivalent. what they do is to transform to frequency domain by using FFT (Fast Fourier Transform) and then perform the multiplication and then go back to the original domain.
I'm writing a function of the Gauss Seidel method of solving a linear system of equations of the form Ax=b, x being the unknown we are looking for.
I am having a problem with the while loop in my function, it seems that it runs infinitely. I can't seem to figure out why.
This is my function for creating the coefficient matrix A and the column vectors x and b, all with the same number of rows of course. No problem with this one.
function [A, b, x0] = test_system(n)
u = ones(n, 1);
A = spdiags([u 4*u u], [-1 0 1], n, n);
b = zeros(n, 1);
b(1) = 3;
b(2 : 2 : end-2) = -2;
b(3 : 2 : end-1) = 2;
b(end) = -3;
x0 = ones(n, 1);
This is my function for solving the system. I have included all of it just in case, but I believe the real problem is within the while loop at the very end which runs infinitely when I execute the function. The counter doesn't break away from it either. I can't really see what its problem is. Any clues?
Be gentle, I'm new at Matlab :)
function [x] = GaussSeidel(A,b,x0,tol)
% implementation of the GaussSeidel iterative method
% for solving a linear system of equations Ax = b
%INPUTS:
% A: coefficient matrix
% b: column vector of constants
% x0: setup for the unknown vector (using vector of ones)
% tol: result must be within 'tol' of correct answer.
%OUTPUTS:
% x: unknown
%check that A is a matrix
if ~(ismatrix(A))
error('A is not a matrix');
end
%check that A is square
[m,n] = size(A);
if m ~= n
error('Matrix A is not square');
end
%check that b is a column vector
if ~(iscolumn(b))
error('b is not a column vector');
end
%check that x0 is a column vector
if ~(iscolumn(x0))
error('x0 is not a column vector');
end
%check that A, b and x0 agree in size
[rowA,colA] = size(A);
[rowb,colb] = size(b);
[rowx0,colx0] = size(x0);
if ~isequal(colA,rowb)||~isequal(rowb,rowx0)
error('matrix dimensions of A, b and xo do not agree');
end
%check that A and b have real entries
if ~isreal(A) || ~isreal(b)
error('matrix A or vector b do not have real entries');
end
%check that the provided tolerance is positive
if tol <= 0
error('tolerance must be positive');
end
%check that A is strictly diagonally dominant
absoluteA = abs(A);
row_sum=sum(absoluteA,2);
diagonal=diag(absoluteA);
if ~all(2*diagonal > row_sum)
warning('matrix A is not strictly diagonally dominant');
end
L = tril(A,-1);
U = triu(A,+1);
D = diag(diag(A));
x = x0;
M1 = inv(D).*L;
M2 = inv(D).*U;
M3 = D\b;
k = 0; %iterations counter
disp(size(M1));
disp(size(M2));
disp(size(M3));
disp(size(x));
while (norm(A*x - b) > tol)
for i=1:n
x(i) = - M1(i,:).*x - M2(i,:).*x + M3(i,:);
end
k=k+1;
if(k >= 10e4)
error('too many iterations carried out');
end
end
end %end function
Coding Discussion
The source of the coding error is the use of element-wise operations instead of matrix-matrix and matrix-vector operations.
These operations produce zero-matrices, so no progress is made.
The M matrices should be defined by
M1 = inv(D)*L; % Note that D\L is more efficient
M2 = inv(D)*U; % Note that D\U is more efficient
M3 = D\b;
and the iterator performing the update should be
x(i) = - M1(i,:)*x - M2(i,:)*x + M3(i,:);
Method Discussion
I also think it is worth mentioning that the code is currently implementing the Jacobi Method since the updater has the form
while a Gauss-Seidel update has the form
.
I don’t have 50 reputation so I can not comment this.
The line if(k >= 10e4), I think this does not make what you think it would. 10e4 is 100,000 and 1e4 is 10,000. This will be the reason why you think your counter does not work. Matlab ist still running because it’s running further than you think it will. Also I run in the same Problem knedlsepp already pointed out.
I am trying to solve a system through Gauss-Seidel Iterative method. But i also want to receive as an answer the iteration matrix that was used. I have this method
function [x0,iter] = gaussSeidel(A,b,iterMax,tol)
D = diag(diag(A));
Lower = -tril(A,-1);
Upper = -triu(A,1);
M = D - Lower;
N = Upper;
n = size(A);
n = n(1);
x0 = ones(n,1);
iter = 1;
for i = 1:1:iterMax
iter = i;
x = M\(N*x0+b);
normC = norm(x-x0,inf);
x0 = x;
if normC <tol
break
end
end
I want to know whats in the iteration matrix ((D-Lower)^(-1))*Upper, but for that I would have to calculate the inverse, and that's computationally expensive, is there another way to get the value?
"\" is an optimized way of solving linear constant coefficient systems by taking inverse.
If you want to see what is the inverse of the coefficient matrix, then you must use
inv(A)
instead of
A\b
There is no way out! Or if you are only dealing with the N th column of the inverse matrix, then you can also use
I=eye(n);
A\I(:,N);