Changing data diagonally in matrix based on formula and table - matlab

Let says I have this matrix:
(x)
X = [1 1 1 0 1 0 0 0;
1 1 0 1 0 1 0 0;
1 0 1 1 0 0 1 0;
0 1 1 1 0 0 0 1;
1 0 0 0 1 1 1 0;
0 1 0 0 1 1 0 1;
0 0 1 0 1 0 1 1;
0 0 0 1 0 1 1 1];
and this table:
kzz
_______
1 80
2 80
3 23
4 14
5 63
6 36
7 41
8 5
and this equation:
f = (1/visc)*((2*kzz2*kzz1*az2*az1)/(kzz2*az2*delz+kzz1*az1*delz)
visc = 2
az2 = 6400
az1 = 6400
delz = 30
kzz1 = ? < From the table
kzz2 = ? < From the table
f = (1/2)*((2*kzz2*kzz1*6400*6400)/(kzz2*6400*30+kzz1*6400*30)
this equation represent the diagonal started from column 5 in the matrix, just below the (X).
The required task is: changing the ones in this diagonal to this equation:
f = (1/2)*((2*kzz2*kzz1*6400*6400)/(kzz2*6400*30+kzz1*6400*30)
For the first value in the diagonal " Matrix(5,1) "
kzz2 = 63 and kzz1 = 80 << which obtained from the table
therefore, the equation will be as follow:
f = (1/2)*((2*63*80*6400*6400)/(63*6400*30+80*6400*30)
so based on the location on matrix, the code should take the value from the table and substitute it in the equation.
My trial is:
k = (4);
d = diag(Matrix,k);
n = d;
n(n==1) = f;
XX = XX - diag(d,k) + diag(n,k);
Example of required output
the output should look like this (imaginary numbers)
1 1 1 0 5 0 0 0
1 1 0 1 0 8 0 0
1 0 1 1 0 0 9 0
0 1 1 1 0 0 0 2
1 0 0 0 1 1 1 0
0 1 0 0 1 1 0 1
0 0 1 0 1 0 1 1
0 0 0 1 0 1 1 1
other equations will be used to change the other diagonals to get this result:
1 2 1 0 5 0 0 0
1 1 0 1 0 8 0 0
1 0 1 6 0 0 9 0
0 1 1 1 0 0 0 2
1 0 0 0 1 7 1 0
0 1 0 0 1 1 0 1
0 0 1 0 1 0 1 4
0 0 0 1 0 1 1 1

Your question is not very clear. If the az1,az2,delz,visc are constants and kzz1=kzz(rowIndex), kzz2=kzz(columnIndex) as it seems to be the case from your example, this seems to be ok for what you are trying to do.
az1 = 6400;
az2 = 6400;
delz = 30;
visc = 2;
i=0;
for j=5:8
i=i+1;
X(i,j) = (1/visc)*(2*kzz(j)*kzz(i)*az2*az1)/(kzz(j)*az2*delz+kzz(i)*az1*delz);
end
If you want to generalize for a diagonal starting at the startColumnIndex, the for loop can be something like that:
i=0;
startColumnIndex = 5;
numberOfColumns = size(X,2);
for j = startColumnIndex : numberOfColumns
i=i+1;
.....stuff you want to do......
end

Related

permutation/combination with specific condition

Let us we have binary number to fill out 9 spots with specific condition: 0 always comes before 1. the possible conditions is 10:
1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1
0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
Now lest us extent it to 0, 1, 2 with same rule. 0 should be always before 1 and/or 2. 1 should be before 1. Again, 9 spots are available to fill out.
I know that this yields to 55 combinations.
Question:
(1) what is the mathematical formulation to generalize this?
(2) How can I store all those 55 combinations? [any matlab code?]
Thanks
As the commenter said, the answer comes down to stars and bars. You can also think of this as counting the number of non-decreasing sequences i_1 <= i_2 <= ... <= i_k, where k is the number of symbols available and each i_j is a number between 0 and 9.
That said, here's a matlab script that generates all possibilities. Each row of the output matrix is one possible string of digits.
function M = bin_combs(L,k)
% L: length
% k: number of symbols
if k == 1
M = zeros(1,L);
else
M = zeros(0,L);
N = bin_combs(L,k-1);
for i = 1:size(N,1)
row = N(i,:);
for j=find(row==k-2)
new_row = row;
new_row(j:end) = new_row(j:end) + 1;
M = [M;new_row];
end
M = [M;row];
end
end
Some sample output:
>> size(bin_combs(9,3))
ans =
55 9
>> size(bin_combs(9,4))
ans =
220 9

Matrix which is 1 when row and column are both odd or both even

I want to create a matrix which which has:
The value 1 if the row is odd and the column is odd
The value 1 if the row is even and the column is even
The value 0 Otherwise.
I want to get the same results as the code below, but in a one line (command window) expression:
N=8;
A = zeros(N);
for row = 1:1:length(A)
for column = 1:1:length(A)
if(mod(row,2) == 1 && mod(column,2) == 1)
A(row,column*(mod(column,2) == 1)) = 1;
elseif(mod(row,2)== 0 && mod(column,2) == 0 )
A(row,column*(mod(column,2) == 0)) = 1;
end
end
end
disp(A)
This is the expected result:
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
A simple approach is to use implicit expansion of addition, noting that
odd+odd = even+even = 0
So this is your answer:
A = 1 - mod( (1:N) + (1:N).', 2 );
You could also do this with toeplitz, as shown in this MATLAB Answers Post
For a square matrix with number of rows = number of columns = N
A = toeplitz(mod(1:N,2));
If the number of rows (M) is not equal to the number of columns (N) then
A = toeplitz(mod(1:M,2),mod(1:N,2))
FWIW, you're asking a specific case of this question:
How to generate a customized checker board matrix as fast as possible?
Can you take three lines?
N=8;
A = zeros(N);
A(1:2:end, 1:2:end) = 1;
A(2:2:end, 2:2:end) = 1;
One line solution (when N is even):
A = repmat([1, 0; 0 1], [N/2, N/2]);
You can try the function meshgrid to generate mesh grids and use mod to determine even or odd
[x,y] = meshgrid(1:N,1:N);
A = mod(x+y+1,2);
such that
>> A
A =
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0
0 1 0 1 0 1 0 1

elimination of consecutive regions

I need to effectively eliminate consecutive regions in vector "a" or better in rows/columns of matrix "A" with length of separate ones regions greater than positive integer N <= length(A):
See following example:
N = 2 % separate consecutive regions with length > 2 are zeroed
a = [0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1]
a_elim = [0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1]
or 2D case:
N = 2
A = [1 0 1 …
1 1 0 …
1 1 0 …
0 0 1 …
1 1 1]
% elimination over columns
A_elim= 0 0 1
0 1 0
0 1 0
0 0 1
1 1 1
% elimination over rows
A_elim= 1 0 1
1 1 0
1 1 0
0 0 1
0 0 0
I am looking for effective vectorized MATLAB function performing this task for size(A) ~ [100000, 1000] (over columns case).
You can use a convolution:
For the 1D case:
N = 2 %tolerance
A = [0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1]
ind = conv(A,ones(N+1,1),'same');
%ind = 1 2 2 1 1 2 3 2 1 1 2 3 3 2 2 1
%A = 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1
ind = conv(ind>N,ones(N+1,1),'same')>0;
%ind = 0 0 0 0 0 1 1 1 0 0 1 1 1 1 0 0
%A = 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1
A(ind) = 0
if N is odd you need an extra step:
ind = conv(A,ones(N+1,1),'same');
ind(find(ind==N+1)+1) = N+1 %the extra step
ind = conv(ind>N,ones(N+1,1),'same')>0;
Generalization for nD dimension:
N = 3 %tolerance
A = round(rand(5,5,5));
for ii = 1:ndims(A)
conv_vec = permute(ones(N+1,1),circshift([1:ndims(A)],ii-1,2))
ind = convn(A,conv_vec,'same')
if mod(N,2) == 1
ind(find(ind==N+1)+1) = N+1
end
ind = convn(ind>N,conv_vec,'same')>0
X = A;
X(ind) = 0
end

Filter islands based on length in a binary array - MATLAB

I have a binary array and I would like to flip values based on the length which they repeat. as an example
Ar = [0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1];
Ideally I would like to flip the 1's which repeat only 2 or fewer times resulting in the following.
Ar = [0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1];
From what I have located online, the Diff function is most commenly used to locate and remove sequences. But from what I have located, it appears to target all instances.
Simply use imopen from Image Processing toolbox with a kernel of 3 ones -
imopen(Ar,[1,1,1])
Sample run -
>> Ar = [0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1];
>> out = imopen(Ar,[1,1,1]);
>> [Ar(:) out(:)]
ans =
0 0
1 0
0 0
0 0
0 0
1 0
1 0
0 0
0 0
0 0
1 1
1 1
1 1
1 1
1 1
0 0
0 0
0 0
0 0
1 1
1 1
1 1
1 1
1 1
1 1
Vectorized solution without using I.P. toolbox -
function out = filter_islands_on_length(Ar, n)
out = Ar;
a = [0 Ar 0];
d = diff(a);
r = find(d);
s0 = r(1:2:end);
s1 = r(2:2:end);
id_arr = zeros(1,numel(Ar));
m = (s1-s0) <= n;
id_arr(s0(m)) = 1;
id_arr(s1(m)) = -1;
out(cumsum(id_arr)~=0) = 0;
Sample runs -
>> Ar
Ar =
0 1 0 0 0 1 1 0 0 0 1 1 1
>> filter_islands_on_length(Ar, 2)
ans =
0 0 0 0 0 0 0 0 0 0 1 1 1
>> filter_islands_on_length(Ar, 1)
ans =
0 0 0 0 0 1 1 0 0 0 1 1 1
Another solution requiring no toolbox but needs Matlab 2016a or later:
n = 3; % islands shorter than n will be removed
Ar = movmax(movsum(Ar,n),[ceil(n/2-1) floor(n/2)])==n;

Using vectorization instead of a 'for Loop' in Matlab

I have a set of 32 bits binary values incoming from a sensor. I have to form all the possible combinations of these values and then convert them into a decimal value.
The code slows down terribly if the incoming rows are more that 80000 - 90000. It takes 120 minutes to run.
I want to optimize this code, since 3 For loops and a function within the innermost loop is slowing down my algorithm. Is there any chance that I can eliminate some For loops and substitute them with vectorizing to speed up the process.
b1 = [0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b2 = [0 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b3 = [0 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1];
b4 = [0 1 0 1 0 1 1 1 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b5 = [0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1];
FullVector = [b1;b2;b3;b4;b5];
for Idx = 1:size(FullVector,1)
k = 1;
MinLength = 4;
MaxLength = 8;
StepSize = 2;
for StartByte = 1:8
for StartBit = 1:8
for SignalLength = MinLength:StepSize:MaxLength
DecimalVals.s(Idx,k) = BitCombinations(FullVector,StartByte,StartBit,SignalLength);
k = k+1;
end
end
end
end
The function:
function decimal = BitCombinations(ByteArray,Sbyte,Sbit,lengthSignal)
%function extracts the required bits from a byte array and
%returns the decimal equivalent of the bits.
%Inputs:
%Sbyte - Starting byte
%Sbit - Starting bit in the given byte
%length - length of bits to be extracted
%Output:
%dec - Returns the dec
startbit_pos = ((Sbyte-1)*8+Sbit);
endbit_pos = ((Sbyte-1)*8+Sbit+lengthSignal-1);
if endbit_pos <= 64
extractedbits = ByteArray(startbit_pos:endbit_pos);
extractedbits = fliplr(extractedbits);
decimal = bi2de(extractedbits);
else
decimal = NaN;
end
end
you should preallocate your result matrix DecimalVals by using the following code example:
b1 = repmat([0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b2 = repmat([0 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b3 = repmat([0 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1],10000,1);
b4 = repmat([0 1 0 1 0 1 1 1 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b5 = repmat([0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1],10000,1);
FullVector = [b1;b2;b3;b4;b5];
MinLength = 4;
MaxLength = 8;
StepSize = 2;
% Preallocation of the result struct
noOfValues = (((MaxLength - MinLength) / 2) + 1) * MaxLength * MaxLength;
DecimalVals = zeros(size(FullVector,1),noOfValues);
for Idx = 1:size(FullVector,1)
k = 1;
for StartByte = 1:MaxLength
for StartBit = 1:MaxLength
for SignalLength = MinLength:StepSize:MaxLength
DecimalVals(Idx,k) = BitCombinations(FullVector,StartByte,StartBit,SignalLength);
k = k+1;
end
end
end
end
result (on my machine):
time consumption without preallocation: 560 seconds
time consumption WITH preallocation: 300 seconds
Furthermore, please use the MATLAB Profiler (Starting the script by using "Run and Time") to identify the bottleneck, respectively which function takes most time and add the function/line to your question.
Unfortunately, I've got no access to the functions of the Communication System Toolbox, so I used the function bi2de from the File Exchange. In this version, there is one sort of error checking, which takes a lot of time: ~230 seconds
Another thing you could do, besides pre-allocating your array, is to not use fliplr. Take a look at this code snippet
tic
N = 10000;
A = [1:N];
for i = 1:N/2
b = A(N-i+1:-1:i);
end
toc
b = [];
tic
for i = 1:N/2
b = fliplr(A(i:N-i+1));
end
toc
Elapsed time is 0.060007 seconds.
Elapsed time is 0.118267 seconds.
So fliplr is around 2x slower to use, rather than simply use "backwards" indexing. I'm pretty sure you would have something to gain also by making your own bi2de function that is specific to your problem.
I made an attempt on this, haven't checked it for efficiency though, but maybe you can use it for your purposes
function values = myBi2Dec(byte,signalLengths)
persistent indexes
if isempty(indexes)
% Find the matrix indexes for this
indexes = [];
for iBit = 1:8
for iSL = signalLengths
if iBit+iSL-1<=8
indexes = [indexes;sub2ind([8,8],iBit,iBit+iSL-1)];
end
end
end
end
% Lets get the cumulative value
cumB2D = cumBi2Dec(byte);
% We already calculated their position, so simply return them
values = cumB2D(indexes);
function cumB2D = cumBi2Dec(byte)
persistent B2D
if isempty(B2D)
B2D = zeros(8,8);
tmp = 2.^[0:7];
for i = 1:8
B2D(i,i:8) = tmp(1:8-(i-1));
end
end
cumB2D = cumsum(repmat(fliplr(byte),8,1).*B2D,2);
Then try, for example, myBi2Dec([0,0,0,0,1,1,1,1],[4:2:8])