Matlab if loop function, How to improve this function? - matlab

I am new to matlab and I am trying to figure how to write the following function in a smart/efficient way.
First I create a matrix y with entries HL, and every line is a permutation of a predefined length n.
For example, for n=3 I get the first line of the matrix y : H H H. Then I want for each line, to create a matrix of size n x n where for example the entry (1,2) corresponds to a variable which links entry y(1,1) with y(1,2) , and entry y(3,2) corresponds to a variable which links entry y(1,3) with y(1,2). Is this possible?
function A1=mystupidfunction(s , n)
%n is the number of agents and s is the number of state, this function
%returns the matrix of influence. Stupid code must be improved to work for
%n agents
x = 'HL'; %// Set of possible types
K = n; %// Length of each permutation
%// Create all possible permutations (with repetition) of letters stored in x
C = cell(K, 1); %// Preallocate a cell array
[C{:}] = ndgrid(x);
y = cellfun(#(x){x(:)}, C);
y = [y{:}];
A1 = sym('A1',[n n], 'positive' );
syms H L A_HH A_HL A_LH A_LL
for k=s
for i=1:n
for j=1:n
if ( y(k,1)==H) && ( y(k,2)==H) && (y(k,3)==H)
A1(i,j)=A_HH
elseif ( y(k,1)==L) && ( y(k,2)==L) && (y(k,3)==L)
A1(i,j)=A_LL
elseif ( y(k,1)==H) && ( y(k,2)==L) && (y(k,3)==L)
A1(1,1)=A_HH
A1(1,2)=A_HL
A1(1,3)=A_HL
A1(2,1)=A_LH
A1(3,1)=A_LH
A1(2,2)=A_LL
A1(2,3)=A_LL
A1(3,3)=A_LL
A1(3,2)=A_LL
elseif ( y(k,1)==H) && ( y(k,2)==H) && (y(k,3)==L)
A1(1,1)=A_HH
A1(1,2)=A_HH
A1(1,3)=A_HL
A1(2,1)=A_HH
A1(3,1)=A_LH
A1(2,2)=A_HH
A1(2,3)=A_HL
A1(3,3)=A_LL
A1(3,2)=A_LH
elseif ( y(k,1)==L) && ( y(k,2)==L) && (y(k,3)==H)
A1(1,1)=A_LL
A1(1,2)=A_LL
A1(1,3)=A_LH
A1(2,1)=A_LL
A1(3,1)=A_LH
A1(2,2)=A_LL
A1(2,3)=A_LH
A1(3,3)=A_HH
A1(3,2)=A_HL
elseif ( y(k,1)==L) && ( y(k,2)==H) && (y(k,3)==H)
A1(1,1)=A_LL
A1(1,2)=A_LH
A1(1,3)=A_LH
A1(2,1)=A_HL
A1(3,1)=A_HL
A1(2,2)=A_HH
A1(2,3)=A_HH
A1(3,3)=A_HH
A1(3,2)=A_HH
elseif ( y(k,1)==L) && ( y(k,2)==H) && (y(k,3)==L)
A1(1,1)=A_LL
A1(1,2)=A_LH
A1(1,3)=A_LL
A1(2,1)=A_HL
A1(3,1)=A_LL
A1(2,2)=A_HH
A1(2,3)=A_HL
A1(3,3)=A_LL
A1(3,2)=A_LH
elseif ( y(k,1)==H) && ( y(k,2)==L) && (y(k,3)==H)
A1(1,1)=A_HH
A1(1,2)=A_HL
A1(1,3)=A_HH
A1(2,1)=A_LH
A1(3,1)=A_HH
A1(2,2)=A_LL
A1(2,3)=A_HL
A1(3,3)=A_HH
A1(3,2)=A_HL
else A(i,j)=0
end
end
end
end
For example when n=3 and s=1, then the function returns:
A =
[ A_HH, A_HH, A_HH]
[ A_HH, A_HH, A_HH]
[ A_HH, A_HH, A_HH]
notes:
C = cell(K, 1); %// Preallocate a cell array
[C{:}] = ndgrid(x); %// Create K grids of values
y = cellfun(#(x){x(:)}, C); %// Convert grids to column vectors
y = [y{:}];
the output is for n=3 :
y =
HHH
LHH
HLH
LLH
HHL
LHL
HLL
LLL
s is just a scalar that indicates the number of line in the matrix y (which corresponds to a "state")

if you only have 2 states H and L, as you said in comment you could just as well use 0 and 1, so a binary logic.
To get your y combinations, just count in binary until you have the right number of digit and convert each bit to the state you decide:
So for order n=3 you would have:
n = 3 ;
a = de2bi( (0:2^n-1).' )
which gives you all 3 digits binary combinations:
a =
0 0 0
1 0 0
0 1 0
1 1 0
0 0 1
1 0 1
0 1 1
1 1 1
If you want them in ascii format, you can then convert them:
b = char( ones(size(a))* 'L') ;
b(~a) = 'H' ;
To obtain:
b =
HHH
LHH
HLH
LLH
HHL
LHL
HLL
LLL
So if you want to keep a "ascii" character logic (and output), this could do the job:
function out = combiadjacent( k , n )
yb = de2bi( (0:2^n-1).' ) ; %'// get the combinations
y = char( ones(size(yb))* 'L') ;
y(~yb) = 'H' ;
A = char( zeros(n,2*n) ) ;
for col=1:n
Acol = [col col+1] + (col-1) ;
A(:,Acol) = [y(k,col)*ones(n,1) y(k,:).'] ;
end
out = reshape( cellstr( reshape(A.',2,[]).' ) , n , n ).' ;
Will give you a cell array as output like:
>> A = combiadjacent( 4 , 3 )
A =
'LL' 'LL' 'HL'
'LL' 'LL' 'HL'
'LH' 'LH' 'HH'
However, if you are not picky about the exact output format, the solution below will probably run significantly faster:
function out = combiadjacent( k , n )
y = de2bi( (0:2^n-1).' ) ; %'// get the combinations
b = ones(n,1)*y(k,:) ;
%// use that to get a cell array of characters
out = cellfun( #(a,b) char(cat(2,a+65,b+65)) , num2cell(b) ,num2cell(b.'),'uni',0) ;
%'// or use that to get a cell array of double in output (even faster)
%// out = cellfun( #(a,b) cat(2,a,b) , num2cell(b) ,num2cell(b.'),'uni',0)
%// or that to get a cell array of boolean
%// out = cellfun( #(a,b) logical(cat(2,a,b)) , num2cell(b) ,num2cell(b.'),'uni',0) ;
Which will give you
>> A = combiadjacent( 4 , 3 )
A =
'BB' 'BB' 'AB'
'BB' 'BB' 'AB'
'BA' 'BA' 'AA'
note: Whatever solution you choose, it would be prudent to add a checking condition for k to make sure the user will not request a line which doesn't exist.

Related

Multiply inverse matrix with another one

I want to multiply two matrices, the first matrix is the inverse of A, and the second matrix is B,
input('Enter The first Matrix')
A = [ 1 2 3 ; 4 5 6 ; 7 8 0 ]
[m n] = size(A)
if m==n
if det(A)==0
disp('inverse does not exist')
else
invv=inv(A)
disp(invv)
end
else
disp('Number of rows and columns are not equel , no inverse')
end
input('Enter The second Matrix')
B = [ 1 ; 1 ; 1 ]
How can I verify that the number of columns in the first matrix is equal to the number of rows in the second matrix, so that they can be multiplied?
function [X] = dot_inv(X,x)
% X - numeric array
% x - cell array of numeric vectors
% DIM - dimensions to omit (asumes ndims(X) = numel(x))
% Y - inner product obtained by summing the products of X and x along DIM
% initialise dimensions
%--------------------------------------------------------------------------
[m n] = size(X)
if m==n
if det(X)==0
error('Error. \n inverse does not exist.')
else
X=inv(X)
end
else
error('Error. \n Number of rows and columns are not equel , no inverse!')
end
if iscell(x)
DIM = (1:numel(x)) + ndims(X) - numel(x);
else
DIM = 1;
x = {x};
end
% inner product using recursive summation (and bsxfun)
%--------------------------------------------------------------------------
for d = 1:numel(x)
s = ones(1,ndims(X));
s(DIM(d)) = numel(x{d});
X = bsxfun(#times,X,reshape(full(x{d}),s));
X = sum(X,DIM(d));
end
% eliminate singleton dimensions
%--------------------------------------------------------------------------
X = squeeze(X);
return

Merge array rows based on the first digit in a column

I have two arrays, A and B. The first digit of each row is the serial number.
How do I combine A and B to have an array C, such that all rows in A with the same serial number in B are concatenated horizontally?
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765 ]
B = [ 23566;
33425;
65438;
75354 ]
y = ismember(A(:,1), B(:,1), 'rows');
t=find(y);
C= [A(t,1:12),B(t,1:12)];
I need C to be:
C = [ 12345, 00000;
23496, 23566;
32673, 33425;
47542, 00000;
54765, 00000;
65436, 00000;
75343, 75354]
My approach would be the following, extract the leading digits of both arrays and compare those:
a=num2str(A)-'0';
b=num2str(B)-'0';
[ida,idb]=ismember(a(:,1),b(:,1));
Now get the sorting index of A
[~,ids]=sort(a(:,1));
Create output array
C=zeros(size(A,1),2);
Finally assign and sort output
C(:,1)=A;
C(ida,2)=B(idb(idb>0));
%sort result
C=C(ids,:)
If it's only the first digit, we only need to check if the first digit (i.e. floor(A/1e4)) matches 0 to 9, and index accordingly...
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zero(; A]; Bz = [0; B];
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, floor( A/1e4 ) );
[~,ib] = ismember( 0:9, floor( B/1e4 ) );
% Assign to C and discard unmatched rows
C = [Az(ia+1), Bz(ib+1)];
C( all( C==0, 2 ), : ) = [];
Note that keeping things numeric with the floor operation should always be preferable to flipping between numeric and character data with things like num2str...
Edit
You changed the scope of the question by commenting with new data. Here is the same method, written to be more generic so it handles A and B with more columns and different magnitude IDs
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zeros(1,size(A,2)); A]; Bz = [zeros(1,size(A,2)); B];
% Function for getting first digit
f = #(x) floor(x./(10.^floor(log10(x))));
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, f(A(:,1)) );
[~,ib] = ismember( 0:9, f(B(:,1)) );
% Assign to C and discard unmatched rows
C = [Az(ia+1,:), Bz(ib+1,:)];
C( all( C==0, 2 ), : ) = [];
First of all, the whole script. At first glance, I couldn't find a solution without using loops.
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765; ]
B = [ 23566;
33425;
65438;
75354; ]
A = sort(A); % Sort A and B.
B = sort(B);
A_str = int2str(A); % Convert integers to chars.
B_str = int2str(B);
A_sn = A_str(:, 1); % Extract first columns.
B_sn = B_str(:, 1); % Basically, these are the serial numbers.
C = zeros(size(A, 1), size(A, 2) * 2); % Initialize C.
C(:, 1) = A; % First column of C is just A.
for i = 1:length(A_sn) % For all serial numbers in A...
for j = 1:length(B_sn) % For all serial numbers in B...
if (A_sn(i) == B_sn(j)) % Check if serial number in B equals the serial number in A.
C(i, 2) = B(j); % If so, set i-th row in C to the corresponding value in B.
end
end
end
C
Results in:
A =
12345
47542
32673
65436
75343
23496
54765
B =
23566
33425
65438
75354
C =
12345 0
23496 23566
32673 33425
47542 0
54765 0
65436 65438
75343 75354

Advanced Encryption Standard (AES) polynomial multiplication in octave / matlab

I am trying to perform polynomial multiplication as explained in the Advanced Encryption Standard (AES) draft.
Here's what I have so far:
function y = multiply_x2( a )
% a is a 1 x 8 binary vector
% y is a 1 x 8 binary vector
% t is a 1 x 8 binary vector corresponding to the "AES irreducible polynomial"
y = [ a(2:8) 0 ]; % Multiply byte 'a' by 2 using "left shift"
t = [ 0 0 0 a(1) a(1) 0 a(1) a(1) ]; % 't' only becomes the "AES irreducible
% polynomial" if a(1) == 1, otherwise
% it becomes the "zero" byte array
y = mod( y + t , 2 ) ; % XOR operation on y and t, as described in AES.
end
The code above is for
"y = {02} . a"
(where "{}" denotes hexadecimal notation, whose binary representation can be interpreted as the presense of the respective power of x in a polynomial. For example, {02} corresponds to 00000010, which corresponds to the polynomial "x", {06} would correspond to "x2+x", etc, as per the AES docs)
I want to multiply a with 0e , 09 , 0d, and 0b.
How will the code be for each of them? i.e. for:
"y= ( {0e} . a )"
"y= ( {09} . a )"
"y= ( {0d} . a )"
"y= ( {02} . a )"
This was an interesting problem. Here is a general solution for multiplication as defined in the AES doc you linked. I use the name xtime for the {02} multiplication, and I implement "addition" (xadd) as an XOR operation (i.e. !=) directly, since this is easier.
Helper functions:
%% in file isByte.m
function Out = isByte (a)
a = a(:).'; % ensure horizontal vector representation
if all (a == 0 | a == 1) && length (a) == 8; Out = true; return; end
Out = false;
end
%% in file byte2hex.m
function Out = byte2hex (a)
a = a(:).'; % ensure horizontal vector
assert (isByte (a), 'Input needs to be a valid "byte" array');
Out = sum (a .* ([2,2,2,2,2,2,2,2] .^ [7:-1:0])); Out = dec2hex (Out);
end
%% in file hex2byte.m
function Out = hex2byte (h)
assert (isxdigit (h) && hex2dec (h) < 256, 'Input needs to be a valid hex number below FF');
Out = dec2bin (hex2dec (h)); Out = sprintf ('%8s', Out);
Out = Out - 48 ; Out(Out == -16) = 0; % convert spaces to zeros
end
Polynomial functions:
%% in file xadd.m
function Out = xadd (a, b)
a = a(:).'; b = b(:).'; % ensure horizontal vector representations
assert (isByte (a) && isByte (b), 'Inputs need to be valid "byte" arrays');
Out = a != b;
end
%% in file xtime.m
function Out = xtime (a)
a = a(:).'; % ensure horizontal vector
assert (isByte (a), 'Input needs to be a valid "byte" array');
Out = [a(2 : 8), 0]; % left shift
if a(1) == 1
Out = xadd (Out, [0, 0, 0, 1, 1, 0, 1, 1]); % subtract (= add) the AES m(x) polynomial
end
end
% in file xmultiply.m
function Out = xmultiply (a, b)
a = a(:)'; b = b(:)'; % ensure horizontal vector representations
assert (isByte(a) && isByte(b), 'Inputs need to be valid "byte" arrays');
Out = [0,0,0,0,0,0,0,0];
if a == [0, 0, 0, 0, 0, 0, 0, 0] || b == [ 0, 0, 0, 0, 0, 0, 0, 0]; return; end
if b(8) == 1; Out = xadd (Out, a); end % yes this could be done recursively but, why bother.
if b(7) == 1; Out = xadd (Out, xtime (a)); end
if b(6) == 1; Out = xadd (Out, xtime (xtime (a))); end
if b(5) == 1; Out = xadd (Out, xtime (xtime (xtime (a)))); end
if b(4) == 1; Out = xadd (Out, xtime (xtime (xtime (xtime (a))))); end
if b(3) == 1; Out = xadd (Out, xtime (xtime (xtime (xtime (xtime (a)))))); end
if b(2) == 1; Out = xadd (Out, xtime (xtime (xtime (xtime (xtime (xtime (a))))))); end
if b(1) == 1; Out = xadd (Out, xtime (xtime (xtime (xtime (xtime (xtime (xtime (a)))))))); end
end
Example use: (same example as in the AES doc)
octave:1> a = hex2byte("57")
a =
0 1 0 1 0 1 1 1
octave:2> b = hex2byte("13")
b =
0 0 0 1 0 0 1 1
octave:3> c = xmultiply(a, b)
c =
1 1 1 1 1 1 1 0
octave:4> byte2hex(c)
ans = FE
In MATLAB/Octave, conv and deconv are respectively correspond to multiplication and (division/modulo) operations for polynomials.
function out = multiply(A, x)
mult = mod(conv(A,x), 2); % poynomial multiplication
[~, modulo] = deconv(mult, [1 0 0 0 1 1 0 1 1]); %modulo operation
out = mod(modulo(end-7:end) , 2); %extract last 8 bits
end
For example to multiply 0x57 and 0x13
a = [1 0 1 0 1 1 1]; %0x57
b = [1 0 0 1 1]; %0x13
result = multiply(a,b)
result =
1 1 1 1 1 1 1 0
that is binary representation of 0xFE
Thank you for your interest. I am trying to implement AES in matlab. And I found the solution in the pages of http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf . Here is the function for the y= ( {09} . a ) multiply operation ;
function y = multiply_x9( a )
% Multiply byte A by 9 over finite field of AES
y2 = multiply_x2( a ) ;
y4 = multiply_x2( y2 ) ;
y8 = multiply_x2( y4 ) ;
y = mod( y8 + a , 2 ) ;
end
And also for the any matrix multiplication multiply_xx (a, b, p ) function can be used. Here is the function;
function y = multiply_xx (a, b, p )
% Determine input lengths and check if they are equal
n = length( a ) ;
if ( n ~= length(b) ) ,
error( 'Operand input lengths not equal to each other!' ) ;
elseif ( n ~= length(p) ) ,
error( 'Operand input lengths not equal to modulus length!' ) ;
end
% Initialize result to zeros and start iteration row by row
y = zeros( 1 , n ) ;
for i = 1 : n ,
m = a(i) * b ;
y = mod( y(1) * p + [ y(2:n) 0 ] + m , 2 ) ;
end
end

Faster way to group data in the same quartile range

Consider a column of a 10 x 10 matrix K, say K(:,1)
I would like to create a 10x4 binary matrix which tells us which quarter range the row entry belongs to. For example
ith row of binary matirx : [ 1 0 0 0 ] => K(i,1)<prctile(K(:,1),25)
My code:
%%%
K = randi(10,10);
BINMAT = zeros(size(K,1),4);
y_1 = prctile(K(:,1),25) ;
ID_1 = find(K(:,1) < y_1);
BINMAT(ID_1,1)=1;
y_2 = prctile(K(:,1),50);
ID_2 = find(( K(:,1) > y_1 & K(:,1) < y_2 ));
BINMAT(ID_2,2)=1;
y_3 = prctile(K(:,1),75);
ID_3 = find(( K(:,1) > y_2 & K(:,1) < y_3 ));
BINMAT(ID_3,3)=1;
y_4 = prctile(K(:,1),100);
ID_4 = find((K(:,1) > y_3 & K(:,1) < y_4 ));
BINMAT(ID_4,4)=1;
%%%
If I have to do this not just for one column but for a set of columns, say A = [ 1 2 5 6], and BINMAT should have 16 columns (4 for each column of K) .Is there a faster way to do this?
You can use a for loop that iterates over the desired column indexes given by A:
K = randi(10,10);
A = [1 2 5 6]; % columns in K to process
BINMAT = zeros(size(K,1), 4*length(A));
cnt = 0; % helper
for col_indx = A
y_1 = prctile(K(:,col_indx),25) ;
ID_1 = find(K(:,col_indx) < y_1);
BINMAT(ID_1, 4*cnt + 1) = 1;
y_2 = prctile(K(:,col_indx),50);
ID_2 = find(( K(:,col_indx) > y_1 & K(:,col_indx) < y_2 ));
BINMAT(ID_2, 4*cnt + 2)=1;
y_3 = prctile(K(:,col_indx),75);
ID_3 = find(( K(:,col_indx) > y_2 & K(:,col_indx) < y_3 ));
BINMAT(ID_3, 4*cnt + 3)=1;
y_4 = prctile(K(:,col_indx),100);
ID_4 = find((K(:,col_indx) > y_3 & K(:,col_indx) < y_4 ));
BINMAT(ID_4, 4*cnt + 4)=1;
cnt = cnt + 1;
end
I have noticed that many of the rows of BINMAT contain only zeros because the code you posted does not take values equal to y_1, y_2, y_3 and y_4 into account. I think you should use K(:,col_indx) >= y_1 ... and so on.
Another suggestion:
K = randi(10,10)
p = 25:25:100;
Y = prctile(K, p);
Y = [zeros(1, size(Y, 2)) ;Y];
BINMAT = zeros(size(K, 1), length(p), size(K, 2));
for j = 1:size(K, 2)
for i = 1:length(p)
BINMAT(Y(i, j) <= K(:,j) & K(:, j) <= Y(i+1, j), i, j) = 1;
end
end
Then, BINMAT(:, :, i) is the binary matrix, as you defined it, for K(:, i).
Percentile is, at its heart, the position of an element in the sorted list. So using sort directly will provide the most efficient solution, since you want multiple percentiles out of multiple columns.
First we need a way to assign fixed bins to the sorted positions. Here's the vector that I think prctile uses, but since 10 doesn't split evenly into 4 bins, it's somewhat arbitrary. (in other words, do you assign element 3 to the 0-25% bin or the 25%-50% bin)? floor(4*(0.5+(0:9).')/10)+1
Now we just need to sort each column, and assign the sort position of each original element to one of those positions. The second output of sort does most of the work:
K = randi(10,10);
A = [1 2 5 6]; % columns in K to process
BINMAT = zeros(size(K,1), 4*length(A));
bins = floor(4*(0.5+(0:9).')/10)+1;
[sortedK, idx] = sort(K(:,A));
% The k'th element of idx belongs to the c(k) bin. So now generate the output.
% We need to offset to the correct block of BINMAT for each column
offset_bins = bsxfun(#plus, bins, 4*(0:length(A)-1));
BINMAT(sub2ind(size(BINMAT), idx, offset_bins)) = 1;

lapack - addressing for fully packed rectangular format

I would like to use the LAPACK routines for factorisation and inversion of matrices using the fully packed rectangular format, as this requires only n(n+1)/2 elements to be stored for a symmetric nxn matrix. So far, I am setting up the matrix in 'packed' format and transform it calling routine DTPTTF. However, this requires a second array. I would like to build my matrix directly in fully packed rectangular format (to save on space) - is there an 'addressing' function which will give me the position of the i,j-th element? or could somebody point me to the relevant formula?
to partly answer my own question: inspecting the source code of DTPTTF and the example given therein, I've worked out the adress for one of the four possible constellations (the only one I need), namely uplo ='L' and trans ='N'. below is my fortran function:
! ==================================== ! returns address for RFP format
integer function ijfprf( ii, jj, n ) ! for row jj and column ii
! ==================================== ! for UPLO = 'L' and TRANSR = 'N' only!
implicit none
integer, intent(in) :: ii, jj, n
integer :: i, j, k, n1, k1
if( ii <= jj ) then
i = ii; j = jj
else
i = jj; j = ii
end if
k = n/2
if( mod(n,2) == 0 ) then ! n even
n1 = n + 1
if( i <= k ) then
ijfprf = 1 + (i - 1) * n1 + j
else
ijfprf = ( j - k - 1 ) * n1 + i - k
end if
else ! n odd
k1 = k + 1
if( i > k1 ) then
ijfprf = ( j - k1 ) * n + i - k1
else
ijfprf = ( i - 1 ) * n + j
end if
end if
return
end function ijfprf