0
votes

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")

1
you need to indent your code.. i submitted an edit, in matlab in the editor toolbar there is an indent section under insert and comment.. if you select all your code then click the green button it does the indentation for you..bilaly
I see some potential for improvement here, but to not mess up the code you need to explain some parts better. 1) What is ndgrid('HL') supposed to be and why are you using ascii equivalent for 72 (H) and 76 (L)? (maybe since H and L are easier to remember?) 2) Is s supposed to be a vector or a scalar? In non of the cases you will need a for loop for k=s since you only store the value for the last iteration (k=s(end)). 3) Have you tried to run this code? I see a lot of places where the code potentially may crash. In that case you should provide the error messages.patrik
@patrik thank you, i will answer you above by editing my question, i can't seem to paste code into a commentMia
@patrik thank you very, I am not using ascii , I have two states in my problem which I call H and L (I could have called them 0 and 1). My code actually gives me the matrix A without an error message but the runtime is quite long and it only works for n=3 (not very smart).Mia

1 Answers

1
votes

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.