Implementing Gaussian elimination with partial pivoting [closed] - matlab

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am writing a program to implement Gaussian elimination with partial pivoting in MATLAB. I created an integer array to store the interchange of rows, instead of directly exchanging the rows.
However, I could not obtain the correct result and I could not figure out the problem. How should I modify my code to get the right answer?
A=[1, -2, 1; 2, 1, -3; 4, -7, 1];
b=[0, 5, 1];
b=b';
function x = GE(A,b)
[m,n]= size(A);
if m ~= n
disp('Not a square');
end
for p=1:n
array(p)=p;
endfor
A = [A,b];
%elimination
for i = 1:n-1
pivot = i;
%select pivot
for j = i+1:n
if abs(A(array(i),i)) < abs(A(array(i),i)) %row interchange
temp = array(i);
array(i) = array(j);
array(j) = temp;
end
end
while (pivot <= n && A(pivot,i)== 0)
pivot = pivot+1;
end
if pivot > n
disp('No unique solution');
break
else
if pivot > i
tem = array(i);
array(i) = pivot
pivot= tem;
end
end
for j = i+1:n
m = -A(array(j),i)/A(array(i),i);
for k = i+1:n+1
A(array(j),k) = A(array(j),k) + m*A(array(i),k);
end
end
end
if A(n,n) == 0
disp('No unique solution');
return
end
%backward substitution
x(n) = A(array(n),n+1)/A(array(n),n);
for i = n - 1:-1:1
sum = 0;
for j = i+1:n
sum = sum + A(array(i),j)*x(j);
end
x(i) = (A(array(i),n+1) - sum)/A(array(i),i);
end
endfunction

Your error is pretty simple. You're not pivoting properly - specifically here inside your if statement:
for j = i+1:n
if abs(A(array(i),i)) < abs(A(array(i),i)) %row interchange <-------
temp = array(i);
array(i) = array(j);
array(j) = temp;
end
end
Your check to see which coefficient to pivot from is not correct because you are using the index i for checking along the columns when you need to use j. Therefore, simply change the other side of your Boolean condition so that it uses j:
for j = i+1:n
if abs(A(array(i),i)) < abs(A(array(j),j)) %// CHANGE HERE
temp = array(i);
array(i) = array(j);
array(j) = temp;
end
end
With your example A and b, the answer I get is x = [2 1 0], which agrees with MATLAB's ldivide operation: x = A \ b.

Related

How to improve this function?

The problem is there are c no. of firms bidding on p no. of projects. The winning bidders should collectively have the lowest cost on the client. Each firm can win a maximum of 2 projects.
I have written this code. It works, but takes forever to produce the result, and is very inefficient.
==========================================================================
function FINANCIAL_RESULTS
clear all; clc;
%This Matlab Program aims to select a large number of random combinations,
%filter those with more than two allocations per firm, and select the
%lowest price.
%number of companies
c = 7;
%number of projects
p = 9;
%max number of projects per company
lim = 2;
%upper and lower random limits
a = 1;
b = c;
%Results Matrix: each row represents the bidding price of one firm on all projects
Results = [382200,444050,725200,279250,750800,190200,528150,297700,297700;339040,393420,649520,243960,695760,157960,454550,259700,256980;388032,499002,721216,9999999,773184,204114,512148,293608,300934;385220,453130,737860,287480,9999999,188960,506690,274260,285670;351600,9999999,9999999,276150,722400,9999999,484150,266000,281400;404776,476444,722540,311634,778424,210776,521520,413130,442160;333400,403810,614720,232200,656140,165660,9999999,274180,274180];
Output = zeros(1,p+1);
n=1;
i=1;
for i = 1:10000000
rndm = round(a + (b-a).*rand(1,p));
%random checker with the criteria (max 2 allocations)
Check = tabulate(rndm);
if max(Check(:,2)) > lim
continue
end
Output(n,1:end-1) = rndm;
%Cumulative addition of random results
for k = 1:p
Output(n,end) = Output(n,end) + Results(rndm(k),k);
end
n = n+1;
end
disp(Results);
[Min_pay,Indx] = min(Output(:,end));
disp(Output(Indx,:));
%You know the program is done when Handel plays
load handel
sound(y,Fs);
%Done !
end
Since the first dimension is much greater than the second dimension it would be more efficient to perform loop along the second dimension:
i = 10000000;
rndm = round(a + (b-a) .* rand(i, p));
Check = zeros(size(rndm, 1), 1);
for k = 1:p
Check = max(Check, sum(rndm == k, 2));
end
rndm = rndm(Check <= lim, :);
OutputEnd = zeros(size(rndm, 1), 1);
for k = 1:p
OutputEnd = OutputEnd + Results(rndm(:, k), k);
end
Output = [rndm OutputEnd];
Note that if the compute has a limited memory put the above code inside a loop and concatenate the results of iterations to produce the final result:
n = 10;
Outputc = cell(n, 1);
for j = 1:n
i = 1000000;
....
Outputc{j} = Output;
end
Output = cat(1, Outputc{:});

How to linearize the nested parfor loop?

I have two variables i,j, where j index start depends on i index.
n = 3;
for i = 1:n
for j = i+1:n
% Feature matching
matches = getMatches(input, allDescriptors{i}, allDescriptors{j});
nf = size(matches, 2);
numMatches(i,j) = nf;
end
end
I am trying to linearize it using the below code:
n = 3;
M = n;
N = n;
parfor i = 1:M*N
% IND2SUB converts from a "linear" index into individual
% subscripts
[ii,jj] = ind2sub([M,N], i);
if (ii~=jj)
matches = getMatches(input, allDescriptors{ii}, allDescriptors{jj});
nf = size(matches, 2);
numMatches(i) = nf;
end
end
But have some entries on the lower triangular part of the square matrix.
Any help is appreciated!

Jacobi method to solve linear systems in MATLAB

How would you code this in MATLAB?
This is what I've tried, but it doesn't work quite right.
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
for k = 1:tot_it
for j = 1:n
for i = 1:n
if (j ~= i)
x(i) = -((A(i,j)/A(i,i)) * x(j) + (b(i)/A(i,i)));
else
continue;
end
end
end
end
end
j is an iterator of a sum over each i, so you need to change their order. Also the formula has a sum and in your code you're not adding anything so that's another thing to consider. The last thing I see that you're omitting is that you should save the previous state of xbecause the right side of the formula needs it. You should try something like this:
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
s = 0; %Auxiliar var to store the sum.
xold = x
for k = 1:tot_it
for i = 1:n
for j = 1:n
if (j ~= i)
s = s + (A(i,j)/A(i,i)) * xold(j);
else
continue;
end
end
x(i) = -s + b(i)/A(i,i);
s = 0;
end
xold = x;
end
end

Jacobi solver going into an infinite loop

I can't seem to find a fix to my infinite loop. I have coded a Jacobi solver to solve a system of linear equations.
Here is my code:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
i =1;
for r=1:m
sum = 0;
for c=1:n
if r~=c
sum = sum + A(r,c)*x(c);
else
x(r) = (-sum + b(r))/A(r,c);
end
x(r) = (-sum + b(r))/A(r,c);
xxx end xxx
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
When I terminate the code it ends at the line with xxx
The reason why your code isn't working is due to the logic of your if statements inside your for loops. Specifically, you need to accumulate all values for a particular row that don't belong to the diagonal of that row first. Once that's done, you then perform the division. You also need to make sure that you're dividing by the diagonal coefficient of A for that row you're concentrating on, which corresponds to the component of x you're trying to solve for. You also need to remove the i=1 statement at the beginning of your loop. You're resetting i each time.
In other words:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
for r=1:m
sum = 0;
for c=1:n
if r==c %// NEW
continue;
end
sum = sum + A(r,c)*x(c); %// NEW
end
x(r) = (-sum + b(r))/A(r,r); %// CHANGE
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
Example use:
A = [6 1 1; 1 5 3; 0 2 4]
b = [1 2 3].';
[x,i] = Jacobi(A, b, [0;0;0], 1e-10)
x =
0.048780487792648
-0.085365853612062
0.792682926806031
i =
20
This means it took 20 iterations to achieve a solution with tolerance 1e-10. Compare this with MATLAB's built-in inverse:
x2 = A \ b
x2 =
0.048780487804878
-0.085365853658537
0.792682926829268
As you can see, I specified a tolerance of 1e-10, which means we are guaranteed to have 10 decimal places of accuracy. We can certainly see 10 decimal places of accuracy between what Jacobi gives us with what MATLAB gives us built-in.

Calculating combinations of paired items with item constraint [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have a set of 120 pairs, which are derived from a set of 16 items (i.e. c(16,2)=120).
I want to determine how many combinations of 56 pairs can be chosen from the 120 pairs, but with the constraint that each combination has to contain exactly 7 of each of the 16 items (i.e. in each subset of 56 pairs, each of the 16 items is equally represented).
In addition to determining the number of combinations, I also need to list them. Can anyone help with how I could code this in Matlab please?
It is an interesting combinitorial question since nchoosek(120,56) gives 7.4149e+34 possible ways to select 56 pairs out of the 120. So you shouldn't solve this by a loop over all selections.
To handle the problem I introduce a representation of selected pairs given by a matrix A = (aij), where aij == 1 if and only if (i,j) oder (j,i) is a pair among the 56 selected ones. This matrix represents a selection of 56 pairs as described above if and only if row sums are 7, i.e. A*ones(16,1) = 7*ones(16,1) (symmetric!). It is easy to solve this systematically to print all possible solutions, but this results in about 1e20 candidates...
But according to this high number you can easily select one example randomly by some stupid code like the following:
%% find some random example
A = zeros(16,16);
b1 = ones(16,1);
b7 = 7*b1;
while norm(A*b1 - b7) ~= 0
A = zeros(16,16);
change = true;
while norm(A*b1 - b7) ~= 0 && change
change = false;
todo = find(A*b1<7);
idx = todo(randperm(length(todo)));
for k = 1:2:length(idx)-1
if A(idx(k),idx(k+1)) == 0
change = true;
end
A(idx(k),idx(k+1)) = 1;
A(idx(k+1),idx(k)) = 1;
end
end
end
%% print it
pIdx = 0;
for lIdx = 1:16
for cIdx = 1:lIdx-1
if A(lIdx,cIdx) == 1
fprintf(['(' num2str(cIdx) ',' num2str(lIdx) ') ']);
pIdx = pIdx + 1;
if mod(pIdx,7) == 0
fprintf('\n');
end
end
end
end
Example result:
(1,3) (2,4) (1,5) (2,5) (2,6) (3,6) (4,6)
(5,6) (1,7) (3,7) (6,7) (4,8) (5,8) (2,9)
(5,9) (6,9) (7,9) (8,9) (2,10) (3,10) (4,10)
(5,10) (7,10) (1,11) (3,11) (6,11) (7,11) (9,11)
(1,12) (4,12) (7,12) (11,12) (3,13) (8,13) (9,13)
(10,13) (1,14) (2,14) (4,14) (8,14) (12,14) (13,14)
(1,15) (3,15) (5,15) (8,15) (11,15) (12,15) (13,15)
(2,16) (4,16) (8,16) (10,16) (12,16) (13,16) (14,16)
Update: Added code to scan all possible solutions...
function main()
%% provide n-choose-k sequences (compute only once!)
global ncks maxResult;
disp('Prepare n choose k sequences...');
for n = 1:15
fprintf([num2str(n) '... ']);
for k = 1:min(7,n)
ncks{n}{k} = nchoosek_sequence(n,k);
end
end
fprintf('\n');
%% start finding solutions
disp('Scan space of solutions...')
A = zeros(16,16);
maxResult = -Inf;
tic;
findMats(A,1)
toc;
end
function findMats(A,curRow)
global ncks maxResult;
remain = 7-sum(A+A');
if curRow == 16
if remain(16) == 0
A = A + A';
if norm(sum(A)-7*ones(1,16)) ~= 0
error('AHHH');
end
%A
%pause();
maxResult = max(YOUR_FUNCTION(A),maxResult); % <- add your function here
end
return;
end
if remain(curRow) == 0
findMats(A,curRow+1);
elseif remain(curRow) > 0
remainingRows = curRow + find(remain(curRow+1:end) > 0);
if ~isempty(remainingRows) && length(remainingRows) >= remain(curRow)
for r = 1:nchoosek(length(remainingRows),remain(curRow))
row = remainingRows(ncks{length(remainingRows)}{remain(curRow)}(r,:));
Anew = A;
Anew(curRow,row) = 1;
findMats(Anew,curRow+1);
end
end
end
end
% very simple and not optimized way to get a sequence of subset-selections
% in increasing order
%
% Note: This function was easy to implement and sufficient for our
% purposes. For more efficient implementations follow e.g.
% http://stackoverflow.com/questions/127704/algorithm-to-return-all-combin
% ations-of-k-elements-from-n
function s = nchoosek_sequence(N,k)
s = zeros(nchoosek(N,k),k);
idx = 1;
for n=(2^k-1):(2^N-1)
if sum(dec2bin(n)=='1') == k
temp = dec2bin(n);
s(idx,:) = find([zeros(1,N-length(temp)), temp=='1']);
idx = idx + 1;
end
end
% just for convinience ;-)
s = s(end:-1:1,:);
end
But this can take a while... ;-)