DGESV gives wrong solution? - matlab

all. I'm trying to solve a Ax=B system in fortran by calling DGESV from lapack.
where,
A =[
1 0 1 0 1 0 1
0 1 0 1 0 1 0
0 0 4 0 32 0 108
0 0 0 24 0 120 0
0 0 0 0 48 0 192
0 0 0 0 0 80 0
0 0 0 0 0 0 120]
B=[
0
0
2
6
0
0
0]
x can be simply calculated in Matlab by x=A\B, which gives
x =
-0.5000
-0.2500
0.5000
0.2500
0
0
0
while I doing the same thing in Fortran, it gives me totally different values. Is there anything wrong with my code or I just make errors in calling DGESV?
Here is my fortran code:
program GG
implicit none
integer, parameter :: N=7
integer :: i,j,ipiv(N),ok
real(8), dimension(1:N,1:N) :: M
real(8), dimension(1,1:N) :: b
M(:,1)=(/1.,0.,1.,0.,1.,0.,1./)*1.d0
M(:,2)=(/0.,1.,0.,1.,0.,1.,0./)*1.d0
M(:,3)=(/0.,0.,2.**3/2,0.,4.**3/2,0.,6.**3/2/)*1.d0
M(:,4)=(/0.,0.,0.,3.*(3.**2-1.),0.,5.*(5.**2-1.),0./)*1.d0
M(:,5)=(/0.,0.,0.,0.,4.*(4.**2-2.**2),0.,6.*(6.**2-2.**2)/)*1.d0
M(:,6)=(/0.,0.,0.,0.,0.,5.*(5.**2-3.**2),0./)*1.d0
M(:,7)=(/0.,0.,0.,0.,0.,0.,6.*(6.**2-4.**2)/)*1.d0
b=reshape((/0,0,2,6,0,0,0/)*1.d0,shape(b))
call DGESV(N,1,M,N,ipiv,b,N,ok)
write(*,*), b
end program GG
the results given by this code is:
0.0000000000000000 0.0000000000000000 0.50000000000000000 0.25000000000000000 -0.33333333333333337 -0.37500000000000000 8.3333333333333315E-002
thanks, sincerely.

The matrix you are creating in Fortran appears to be the transpose (rows and columns flipped) of the one you define in MATLAB. Note (in MATLAB):
>> A = [1 0 1 0 1 0 1
0 1 0 1 0 1 0
0 0 4 0 32 0 108
0 0 0 24 0 120 0
0 0 0 0 48 0 192
0 0 0 0 0 80 0
0 0 0 0 0 0 120];
>> B = [0 0 2 6 0 0 0];
>> x = A\B.'
x =
-0.5000
-0.2500
0.5000
0.2500
0
0
0
>> x = (A.')\B.' % A is transposed, and you get your Fortran result
x =
0
0
0.5000
0.2500
-0.3333
-0.3750
0.0833
In other words, doing M(:,1)=... in Fortran fills the first column, not the first row. If you flip them to M(1,:)=... and so forth, I think it should match the results from MATLAB.

Related

MATLAB: Create a block diagonal matrix

I have a formula for creating a system of equations in matrix form.and wrote it like below:
for i=1:n+1
for j=1:n+1
t(i)=(1/2)*(1+cos(((2*(n-i)+3)*pi)/(2*(n+1))));
y(i,j)=t(i)^(j-1);
end
end
now what I have to do is creating a block diagonal matrix with rows of y separately in each block. i mean each row of y that contain powers of just t(i) should repeat three times in each block, then next row be the next block with three rows. like this:
T=[y(t1) 0 0;0 y(t1) 0;0 0 y(t1); ... ;y(t n+1) 0 0;0 y(tn+1) 0;0 0 y(tn+1)]
So since I can't comment in formated mode I try to interprete your question the following way:
So if
y =
1 2
3 4
Interpretation possibility a) is
T =
1 2 0 0 0 0 3 4 0 0 0 0
0 0 1 2 0 0 0 0 3 4 0 0
0 0 0 0 1 2 0 0 0 0 3 4
or this b)
T =
1 2 0 0 0 0 0 0 0 0 0 0
0 0 1 2 0 0 0 0 0 0 0 0
0 0 0 0 1 2 0 0 0 0 0 0
0 0 0 0 0 0 3 4 0 0 0 0
0 0 0 0 0 0 0 0 3 4 0 0
0 0 0 0 0 0 0 0 0 0 3 4
Solution
You first create one block i.e.
1 2 0 0 0 0
0 0 1 2 0 0
0 0 0 0 1 2
by calculating temp{1} = kron(I, y(1,:)), where I = eye(3). You then do the same operation for the second row: temp{2} = kron(I,y(2,:)) and so on. This procedure can be done easily in a for-loop:
I = eye(3);
temp = cell(1,size(y,1));
for i = 1:size(y,1)
temp{i} = kron(I, y(i,:));
end
Option a)
The result is now just: [temp{:}].
Option b)
Here the result is: blkdiag(temp{:})
you know, I had a problem for making a system of linear equations.maybe what I wrote above in calculating the y(i) just make it difficult for me.
for the example you said, I have this:
n=3
form equation above:
t1=0.0381
t2=0.3087
t3=0.6913
t4=0.9619
now,
y(t)=[1 t t^2 t^3 t^4]
I mean
y(t1)=[1.0000 0.0381 0.0014 0.0001]
y(t2)=[1.0000 0.3087 0.0953 0.0294]
y(t3)=[1.0000 0.6913 0.4780 0.3304]
y(t4)=[1.0000 0.9619 0.9253 0.8901]
but, since I couldn't calculate every y(i) seperately, wrote it in this form
y=[1.0000 0.0381 0.0014 0.0001
1.0000 0.3087 0.0953 0.0294
1.0000 0.6913 0.4780 0.3304
1.0000 0.9619 0.9253 0.8901]
now, should have two matrices. one:
s=[y(t) 0 0;0 y(t) 0;0 0 y(t)]
r=[s(t1) ... 0; ... ;0 ... s(tn+1)]
second:
d=[ 1 -1 1 -1
0 2 -8 18
0 0 8 -48
0 0 0 32]
k=y*d
u=[0 0 0;0 k 0;0 0 0]
a=[u(t1) ... 0; ... ;0 ... u(tn+1)]
and these matrices, r and a, should have 3(n+1) columns (in this example 12 columns).
I hope it could help

How to solve linear algebra equation AC=D where A is non-square matrix [duplicate]

This question already has answers here:
How to perform inverse in GF(2) and multiply in GF(256) in Matlab?
(2 answers)
Closed 7 years ago.
I have a binary matrix A (only 1 and 0), and a vector D in Galois field (256) The vector C is calculated as:
C = (A^^-1)*D
where A^^-1 denotes the inverse matrix of matrix A in GF(2), * is multiplication operation. The result vector C must be in GF(256).
However, I only have a matrix A1 is non-square matrix. The above matrix A in the equation is created by delete some dependence rows of A1. In same manner, the vector D is constructed by delete some element corresponding the deleted rows in A1. Hence, we can solve above equation. My question is that can we have any function in MATLAB to do above steps?
For example, I have A1 is 16x14 matrix, D1 is 16x1 vector
A1 =[1 0 0 1 1 0 0 0 0 0 0 0 0 0
1 1 0 0 0 1 0 0 0 0 0 0 0 0
1 1 1 0 0 0 1 0 0 0 0 0 0 0
0 1 1 1 0 0 0 1 0 0 0 0 0 0
0 0 1 1 0 0 0 0 1 0 0 0 0 0
1 1 0 1 1 0 0 1 0 1 0 0 0 0
1 0 1 1 0 1 0 0 1 0 1 0 0 0
1 1 1 0 0 0 1 1 1 0 0 1 0 0
0 1 1 1 1 1 1 0 0 0 0 0 1 0
0 0 0 0 1 1 1 1 1 0 0 0 0 1
0 1 1 1 1 0 1 1 1 0 1 1 1 0
0 0 0 1 0 0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 1 0 0 0 0 0 0
1 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 1 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 1 ]
D1=[0; 0; 0; 0 ; 0; 0 ; 0; 0 ; 0 ; 0 ; 103 ; 198 ; 105 ; 115; 175 ; 14]
In above example, we need to delete two dependence rows/cols from A1 to obtain A is 14x14 matrix and D1 also delete 2 elements to obtain D, and then my expected result is
C=A^^-1*D
C= [ 103; 187 ; 125; 210 ; 181; 220 ; 161 ; 20 ; 175; 175; 187; 187 ; 220 ; 115]
This is what I tried
%%A1=gf(A1,8);
%%D1=gf(D1,8); %%2^8=256
%% Do something and last step is
%%C=inv(A)*D
[C,vld] = gflineq(A1,D1,8)
Or
C=gf(A1,8) \ gf(D1,8)
However, these ways did not return the my expected C vector. I found that Gaussian Elimination can be worked, but I don't know how can I apply for my case. Could you give me a correct solution?
First of all, I don't have access to the "Communication system toolbox", so in order to operate in GF(2) I have to add mod(stuff,2) calls in the code, and in order to operate in GF(2^8) I had to implement a function that sums in this field. Just define your variables with gf and remove these calls if you have access to the toolbox.
Prerequisite : Summing in GF(2^8) :
Summing in GF(2^8) is not trivial, as it behaves like (Z/2Z)^8.
In order to sum in this field, I have the following function.
Basically, elements in GF(2^8) are 8-tuples, each element taking a value in {0,1}. For example, (1,1,0,0,0,1,1,0) is one of them. In order to sum two tuples in this field, ones has, for each element to take the sum in Z/2Z.
For example, if we want the sum of (0,0,0,1,0,0,0,1) and (1,1,1,1,1,1,1,1) : (Remember that in Z/2Z, 0+0=0 , 0+1=1 , 1+0=1 and 1+1=0)
First elements of these tuple are 0 and 1, so the first element of the sum will be 0+1=1. Do this with all elements and you obtain :
(0,0,0,1,0,0,0,1)+(1,1,1,1,1,1,1,1)=(1,1,1,0,1,1,1,0)
The function operates the same way :
1) Transform inputs into binary numbers
2) Compare each digit. If they're equal they sum up to 0 (0+0=0 , 1+1=0), if not they sum up to 1 (0+1=1 and 1+0=1).
3) Transform result back into decimal numbers
function [D] = SumInGF256(D1,D2)
%UNTITLED3 Summary of this function goes here
% Detailed explanation goes here
A=size(D1);
P=numel(D1);
D=zeros(A);
D1=dec2bin(D1,8);
D2=dec2bin(D2,8);
% TmpD=cell(A);
for jj=1:P
TmpD1=D1(jj,:);
TmpD2=D2(jj,:);
out='';
for ii=1:8
if isequal(TmpD1(ii),TmpD2(ii))
out=strcat(out,'0');
else
out=strcat(out,'1');
end
end
D(jj)=bin2dec(out);
end
Gaussian elimination in GF(2) works exactly the same way in essance than in R or C, except it's much easier due to the fact that 1+1=0. Here's the code :
A1 =[1 0 0 1 1 0 0 0 0 0 0 0 0 0;...
1 1 0 0 0 1 0 0 0 0 0 0 0 0;...
1 1 1 0 0 0 1 0 0 0 0 0 0 0;...
0 1 1 1 0 0 0 1 0 0 0 0 0 0;...
0 0 1 1 0 0 0 0 1 0 0 0 0 0;...
1 1 0 1 1 0 0 1 0 1 0 0 0 0;...
1 0 1 1 0 1 0 0 1 0 1 0 0 0;...
1 1 1 0 0 0 1 1 1 0 0 1 0 0;...
0 1 1 1 1 1 1 0 0 0 0 0 1 0;...
0 0 0 0 1 1 1 1 1 0 0 0 0 1;...
0 1 1 1 1 0 1 1 1 0 1 1 1 0;...
0 0 0 1 0 0 0 1 0 0 0 0 0 0;...
0 0 1 0 0 0 0 1 0 0 0 0 0 0;...
1 1 1 1 0 0 0 0 0 0 0 0 0 0;...
0 0 1 1 0 0 0 0 1 1 0 0 0 0;...
0 0 1 0 0 0 0 0 0 0 0 0 0 1 ];
D1=[0; 0; 0; 0 ; 0; 0 ; 0; 0 ; 0 ; 0 ; 103 ; 198 ; 105 ; 115; 175 ; 14];
for ii=1:14
% Find ii-th pivot index between row ii and last row
PivIndex=find(A1(ii:end,ii),1)+ii-1;
% Switch ii-th row with Pivot row
A1([ii PivIndex],:)=A1([PivIndex ii],:);
D1([ii PivIndex])=D1([PivIndex ii]);
% Find all rows other than row ii containing a 1 in column ii
RowIndexes=find(A1(:,ii));
RowIndexes(RowIndexes==ii)==[];
% Add row ii to all rows in RowIndexes, do the same in D
A1(RowIndexes,:)=mod(A1(RowIndexes,:)+repmat(A1(ii,:),numel(RowIndexes),1),2);
%% Problem with my answer was here, as the sum in GF(256) doesn t work like that. (GF(256),+) behaves like ((Z/2Z)^8,+)... See prequisite for summing in GF(256)
% D1(RowIndexes)=mod(D1(RowIndexes)+repmat(D1(ii),numel(RowIndexes),1),256);
D1(RowIndexes)=SumInGF256(D1(RowIndexes),repmat(D1(ii),numel(RowIndexes),1));
end
% Now A1 is diagonal, with both last rows being zero. Problem is D
% has to be 0 aswell on the 2 last positions to get 0=0..
% Check if D(15:16)==[0;0] if not the system has no solution
if isequal(D1(15:16),[0;0])
A2=A1(1:14,:);
C=D1(1:14)
else
disp('No solution')
end
Here the output is as you wanted :
C =
103 187 125 210 181 220 161
20 175 175 187 187 220 115
First of all, I would like thank BillBokeey for your work. However, I am working in GF(256), it is more complex than GF(2). After google, I find a good solution for my case. This is source code for rfc-6330. In that source code, he had a function that is rfc6330_gaussian. For my question above, it is easy to apply it by
C=rfc6330_gaussian( A1, D1 )
So the result will be similar my expected result
C=[ 103
187
125
210
181
220
161
20
175
175
187
187
220
115]
This ans. will be useful for anyone who has similar my issue.

Creating big size diagonal matrix

I have a 512x512 random matrix which I want to put elements of it on the main diagonal of another matrix which elements are all zero so that my diagonal matrix would be 262144x262144.Of course it gives me low memory error.I also tried sparse function but it also does not work.Can anyone help me with this?
here is the code:
A=randn(512,512);
A=A(:);
Z=sparse(diag(A));
Not an expert on sparse matrices, but looking at the docs, I believe you can do something like this -
sparse(1:262144,1:262144,A(:))
Sample run -
>> A
A =
1 7 4
8 7 6
9 7 2
>> n = 9
n =
9
>> sparse(1:n,1:n,A(:))
ans =
(1,1) 1
(2,2) 8
(3,3) 9
(4,4) 7
(5,5) 7
(6,6) 7
(7,7) 4
(8,8) 6
(9,9) 2
>> full(sparse(1:n,1:n,A(:)))
ans =
1 0 0 0 0 0 0 0 0
0 8 0 0 0 0 0 0 0
0 0 9 0 0 0 0 0 0
0 0 0 7 0 0 0 0 0
0 0 0 0 7 0 0 0 0
0 0 0 0 0 7 0 0 0
0 0 0 0 0 0 4 0 0
0 0 0 0 0 0 0 6 0
0 0 0 0 0 0 0 0 2

what do the commas in (cl,:,k) in MATLAB do, when building a matrix

I know how to build a matrix within MATLAB but the example I am working on has is defined as
a(cl,:,k)=x*ang;
cl, k, x and ang are already defined. I just wondered what the (cl,:,k) does, in particular the role of the commas?
Also, if I were to replicate this within Excel then how would I do so?
The comma , in a(cl,:,k) is to separate different dimensions of the matrix a.
The colon : in a(cl,:,k) is to select all elements along this dimension (restricted by other dimensions), which is shorthand notation for 1:end. In other words, all elements a(cl, 1:end, k) are selected, where end is the size of the second dimension of a.
For example:
a = zeros(2, 3); // 2x3 matrix with all elements are 0
a(1, :) = [1 2 3]; // <=> a(1,1:3)=[1 2 3]; assign all elements to the first row
then, a will be
1 2 3
0 0 0
The commas separate the indices along different axes of the elements of the multi dimensional array you want to access
: means 1:end - here end will become the largest index possible along that axis
>> a = zeros(3,3,3)
a(:,:,1) =
0 0 0
0 0 0
0 0 0
a(:,:,2) =
0 0 0
0 0 0
0 0 0
a(:,:,3) =
0 0 0
0 0 0
0 0 0
>> a(1,:,1) = 1
a(:,:,1) =
1 1 1
0 0 0
0 0 0
a(:,:,2) =
0 0 0
0 0 0
0 0 0
a(:,:,3) =
0 0 0
0 0 0
0 0 0
>> a(2,1:end,2) = 2
a(:,:,1) =
1 1 1
0 0 0
0 0 0
a(:,:,2) =
0 0 0
2 2 2
0 0 0
a(:,:,3) =
0 0 0
0 0 0
0 0 0
>> a(1,1,:) = 5
a(:,:,1) =
5 1 1
0 0 0
0 0 0
a(:,:,2) =
5 0 0
2 2 2
0 0 0
a(:,:,3) =
5 0 0
0 0 0
0 0 0

Please help me to test my hypothesis with the neighbor elements in the matrix

I could not figure out the last part of my research so if anyone could help me I would be really appreciated for the help.. :)
Say that my original matrix is,
X =
0 0 0 0 0
0 0 12 9 0
0 4 9 15 0
0 11 19 0 0
0 2 4 8 0
0 4 5 8 0
0 0 0 0 0
and after finding the average of the non-zeros I will get something like below:
new_x =
0 0 0 0 0
0 0 **9.0000** 9.0000 0
0 4.0000 9.0000 **9.0000** 0
0 **8.3333** **8.0000** 0 0
0 2.0000 4.0000 8.0000 0
0 4.0000 5.0000 8.0000 0
0 0 0 0 0
Note that any elements that are greater than 10 are the 'center' and we want to find the average of the non-zeros with the radius of say 1 m. where 1 meter = 1 element away from the center.
** ** means the center.
For this part I have used the following (from gnovice):
X=[0 0 0 0 0; 0 0 12 9 0; 0 4 9 15 0; 0 11 19 0 0;
0 2 4 8 0; 0 4 5 8 0; 0 0 0 0 0];
kernel=[0 1 0; 1 0 1; 0 1 0];
sumx=conv2(X,kernel,'same');
nx=conv2(double(X>0),kernel,'same');
index=(X>10);
new_x=X;
new_x(index)=sumx(index)./max(nx(index),1);
So my question is that I want to compare the neighbor elements with its center whether they are equal, lesser, or greater. If it is greater or equal then '1' or else '0'.Also whatever elements that are outside the radius can be ignored and replaced with '0'.
For example, the 9 in the middle is within the radius of 12, 15, and 19 centers, so take the minimum center of those `min[9.000, 9.000, 8.000] = 8.000.
In this case 4 will not take into the consideration as it is not called the 'center' as well as [ 8 4 5 and 8 ] in the last two rows.
So I want something like below:
Test_x =
0 0 0 0 0
0 0 1 1 0
0 0 1 1 0
0 1 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
I have put this first part in the forum before and I am really appreciated for every suggestion earlier.
Please give me some ideas to start with. I have tried using a loop but it didnt seem to work very well. Any MATLAB function that can do the job for me..
Thank you so much for the help.
Beginner at MATLAB
I think I found the solution for this question by using Jonas techniques. Thank you for the help Jonas and gnovie:)
X=[0 0 0 0 0; 0 0 12 9 0; 0 4 9 15 0; 0 11 19 0 0; 0 2 4 8 0; 0 4 5 8 0; 0 0 0 0 0];
kernel=[0 1 0; 1 0 1; 0 1 0];
sumx=conv2(X,kernel,'same');
nx=conv2(double(X>0),kernel,'same');
avg_x=X;
avg_x(avg_x<10)=0;
index=(avg_x>10);
avg_x(index)=sumx(index)./max(nx(index),1);
avg_x =
0 0 0 0 0
0 0 9.0000 0 0
0 0 0 9.0000 0
0 8.3333 8.0000 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
tmp_x=avg_x;
maxVal=max(avg_x(:))+1;
tmp_x(tmp_x==0)=maxVal;
tmp_x=imerode(tmp_x,kernel);
Test_x=X>=tmp_x;
I think what you want to do is create a new array based on new_x that replaces every element by the minimum of its 4-connected neighbours. Then you can compare the new array to new_x.
Here's a way to do this (requires the image processing toolbox)
tmp_x = new_x;
maxVal = max(new_x(:))+1;
tmp_x(tmp_x == 0) = maxVal; %# replace all the zeros in tmp_x with something large
tmp_x = imerode(tmp_x,kernel); %# kernel is the same as in the OP
Test_x = new_x >= tmp_x; %# put ones wherever the value is
%# greater or equal the neighbour's minimum
%# only keep 1's that are next to 'centers'
Test_x = Test_x .* imdilate(X>10,strel('disk',1))
Test_x =
0 0 0 0 0
0 0 1 1 0
0 0 1 1 0
0 1 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
Note that I get one more ones with this logic than you do.