Creating a graph using maple - maple

What is the (maple) code for the following graph: The vertices are the elements of M_2(\mathbb{Z}_2) and two vertices A and B are adjacent if and only if AB = I.
If you know the code or any references, please let me know.

Start step by step. Think what you need. You need to define your set of vertices and then set of edges. First with the set of vertices. You want all matrices of size 2 by 2 with binary entries, it means a finite set of 16 elements. Matrices are defined in Maple. You can define a matrix with entries (1,1), (1,2), (2,1) and (2,2) beign a, b, c and d respectively in one of the following two ways.
M := Matrix([ [a, b], [c, d] ]);
which means row-wise, or column-wise as in below.
M := < < a, b > | < c, d > >;
Now, I want to put them in an ordered collection, so I choose list data structure. You can make an empty list and then add the matrices one by one with for-loops to it, but since lists are immutable data structures, I would use Array instead and then convert it to a list in the end. Another way is to use list-comprehension using seq. Here is how I do it.
V := [ seq( seq( seq( seq( Matrix([ [a, b], [c, d] ]), d = 0..1 ), c = 0..1 ), b = 0..1 ), a = 0..1 ) ];
And you will see a beautiful list with all 16 matrices that you expect.
Now for the set of edges. Your set is small, so going for a command to find the inverse is not really necessary, just have a nested for-loop to actually multiply matrices A and B and then compare if the result is the identity matrix or not. Remember that in Maple = is not a mathematical equality comparison. To check whether two matrices are equal, use the Equal command in the LinearAlgebra package. So here is how I do it.
E := Array([]); # empty 1-dimensional array
for A in V do
for B in V do
if LinearAlgebra:-Equal( ( A . B mod 2 ) , Matrix([ [1, 0], [0, 1] ]) ) then
ArrayTools:-Append( E, [A, B] ): # modifying E itself instead of defining new one.
end if:
end do:
end do:
Now if you ask to see E, you will see 6 ordered pairs of matrices that their product is the the identity matrix. Note the use of mod to have remain in GF(2) (binary field). If you do the multiplications and additions in Z and then take mod 2, the result will be the same as if you were doing the multiplications and additions in GF(2) from the beginning.
Technically you already have your graph and if you don't want to do anything further, that is the end. The ordered pair (V, E) is the graph itself. But Maple has a package dedicated to Graph theory called GraphTheory. If you want to have a Graph object that you can apply the commands of this package on it, then you need to convert the array of edges to a set. Remember that having the edges stored as ordered pairs (list of length 2) will tell Maple that your edges are directed. If you want undirected edges, then use set of length 2. The following line define the graph object for this example.
E := convert( E, set );
G := GraphTheory:-Graph( V, E );
However, you will get an error message. That is because the elements in your vertices set must be integers or strings or something else, but not matrices, it seems the developers didn't support matrices as label of vertices or something like that. So now instead of saving nodes of the graph as matrices, I pick up the integer indices of them as members of V. For example the identity matrix is the 10th element of V (if you have used the same loop code that I used to generate V above). So instead of asking Maple to have [1 0\\ 0 1] as a vertex of G, I will ask it to have 10 as this vertec, and the edge connecting this node to itself, will be [10, 10]. So I redefine E and V for G.
E := Array([]);
for i from 1 by 1 to 16 do
for j from 1 by 1 to 16 do
if LinearAlgebra:-Equal( ( V[i] . V[j] mod 2 ) , Matrix([ [1, 0], [0, 1] ]) ) then
ArrayTools:-Append( E, [i, j] ):
end if:
end do:
end do:
E := convert( E, set );
G := GraphTheory:-Graph( [ seq(i, i = 1..16) ], E );
No error message this time :)
Now what can we do with this G? The first thing you may want to try is to draw it. Here is how you can do it using GraphTheory's predefined commands.
GraphTheory:-DrawGraph( G );
Here is the picture you get from Maple.
Note that in this case direction was not very important as every edge is two-sided, but in general matrix-multiplication is not commutative so in a different case (if your edge definition is different) you may want to keep the direction and also that is why I did not simplify the nested-loops for E to a n(n-1)/2 cases and kept the whole n^2 cases.

Related

vectorized block assign with overlopping values

So I ran into this bug today
A_TEST(dest,:)=A_TEST(source,:)+A_TEST(dest,:);
A_TEST(:,dest)=A_TEST(:,source)+A_TEST(:,dest);
If dest is non-unique, this fails (which makes sense). So my quick fix is to do a for loop over dest
for (k=1:numel(dest))
A(dest(k),:)=A(source(k),:)+A(dest(k),:);
A(:,dest(k))=A(:,source(k))+A(:,dest(k));
end
And matlab is bad at such for loops. How would one vectorize this call?
With the following, I show how to do it with rows.
To do it with columns, it's a similar approach but different code, I'll explain why.
To summarize, you have a matrix A, with n rows and p columns.
You have a list of integers in the range [1,n], src, and idem for dst.
I'm assuming that they both have the same size, and might contain more than n elements (so that there are repetitions in both potentially).
Grouping the srcs by dsts, it's clear that the operation you're talking about is equivalent to a linear recombination of rows. This is equivalent to a pre-multiplication by a n x n matrix in which element (i,j) = k means "the recombination corresponding to the destination row i contains row j with multiplicity k".
This is what the following code does:
function A = madScience( A, src, dst )
n = size(A,1);
M = eye(n);
ix = sub2ind( [n,n], dst, src );
[ux,~,mlt] = unique( ix );
nux = length(ux);
mlt = accumarray( mlt(:), 1, [nux,1] );
M(ux) = M(ux) + mlt';
A = M*A;
end
Note 1: The two codes that you give in your post are NOT equivalent; you would need two separate for loops to make them equivalent.
Note 2: The same operation on columns is equivalent to a post multiplication by a matrix in which element (i,j) = k means "the recombination corresponding to column j contains column i with multiplicity k".
Note 3: If A is square, then both operations can be performed with the same matrix M as (M*A) * M' (the parenthesis are important).

Multidimensional Arrays Multiplication in Matlab

I have the following three arrays in Matlab:
A size: 2xMxN
B size: MxN
C size: 2xN
Is there any way to remove the following loop to speed things up?
D = zeros(2,N);
for i=1:N
D(:,i) = A(:,:,i) * ( B(:,i) - A(:,:,i)' * C(:,i) );
end
Thanks
Yes, it is possible to do without the for loop, but whether this leads to a speed-up depends on the values of M and N.
Your idea of a generalized matrix multiplication is interesting, but it is not exactly to the point here, because through the repeated use of the index i you effectively take a generalized diagonal of a generalized product, which means that most of the multiplication results are not needed.
The trick to implement the computation without a loop is to a) match matrix dimensions through reshape, b) obtain the matrix product through bsxfun(#times, …) and sum, and c) get rid of the resulting singleton dimensions through reshape:
par = B - reshape(sum(bsxfun(#times, A, reshape(C, 2, 1, N)), 1), M, N);
D = reshape(sum(bsxfun(#times, A, reshape(par, 1, M, N)), 2), 2, N);
par is the value of the inner expression in parentheses, D the final result.
As said, the timing depends on the exact values. For M = 100 and N = 1000000 I find a speed-up by about a factor of two, for M = 10000 and N = 10000 the loop-less implementation is actually a bit slower.
You may find that the following
D=tprod(A,[1 -3 2],B-tprod(A,[-3 1 2],C,[-3 2]),[-3 2]);
cuts the time taken. I did a few tests and found the time was cut in about half.
tprod is available at
http://www.mathworks.com/matlabcentral/fileexchange/16275
tprod requires that A, B and C are full (not sparse).

Mapping ids of two vectors

I have two vectors with the same elements but their order is not same. For eg
A
10
9
8
B
8
9
10
I want to find the mapping between the two
B2A
3
2
1
How can I do this in matlab efficiently?
I think the Matlab sort is efficient. So:
[~,I]=sort(A); %sort A; we want the indices, not the values
[~,J]=sort(B); %same with B
%I(1) and J(1) both point to the smallest value, and a similar statement is true
%for other pairs, even with repeated values.
%Now, find the index vector that sorts I
[~,K]=sort(I);
%if K(1) is k, then A(k) is the kth smallest entry in A, and the kth smallest
%entry in B is J(k)
%so B2A(1)=J(k)=J(K(1)), where BSA is the desired permutation vector
% A similar statement holds for the other entries
%so finally
B2A=J(K);
if the above were in script "findB2A" the following should be a check for it
N=1e4;
M=100;
A=floor(M*rand(1,N));
[~,I]=sort(rand(1,N));
B=A(I);
findB2A;
all(A==B(B2A))
There are a couple of ways of doing this. The most efficient in terms of lines of code is probably using ismember(). The return values are [Lia,Locb] = ismember(A,B), where Locb are the indices in B which correspond to the elements of A. You can do [~, B2A] = ismember(A, B) to get the result you want. If your version of MATLAB does not allow ~, supply a throwaway argument for the first output.
You must ensure that there is a 1-to-1 mapping to get meaningful results, otherwise the index will always point to the first matching element.
Here a solution :
arrayfun(#(x)find(x == B), A)
I tried with bigger arrays :
A = [ 7 5 2 9 1];
B = [ 1 9 7 5 2];
It gives the following result :
ans =
3 4 5 2 1
Edit
Because arrayfun is usually slower than the equivalent loop, here a solution with a loop:
T = length(A);
B2A = zeros(1, length(A));
for tt = 1:T
B2A(1, tt) = find(A(tt) == B);
end
I would go for Joe Serrano's answer using three chained sort's.
Another approach is to test all combinations for equality with bsxfun:
[~, B2A] = max(bsxfun(#eq, B(:), A(:).'));
This gives B2A such that B(B2A) equals A. If you want it the other way around (not clear from your example), simply reverse A and B within bsxfun.

Maximum of a subset of array (MATLAB)

Suppose in MATLAB I have a real matrix A which is n x m and a binary matrix B of the same size. The latter matrix defines the optimization set (all indices for which the element of B equals one): over this set I would like to find the maximal element of A. How can I do this?
The first idea I had is that I consider C = A.*B and look for the maximal element of C. This works fine for all matrices A which have at least one positive element, however it does not work for matrices with all negative elements.
You can do
C = A(B==1);
to give you an array of just the values of A corresponding to a value of 1 in B. And
max( C )
will give you the maximum value of A where B is 1
With this method you don't run into a problem when all values of A are negative as the zeros don't appear in C.
Obviously you can condense this to
desiredValue = max(A(B(:)==1));
I am using the colon operator to make sure that the result of A(B(:)==1) is a column vector - if B is all ones I am not sure if Matlab would return a vector or a nxm matrix (and I can't confirm right now).
update to get the index of the value, you can do:
f = find(B==1);
[m mi] = max(A(f));
maxIndex = f(mi);
And to get that back to the 2D elements:
[i j] = ind2sub(size(A), maxIndex);

Efficient way of mapping similar inputs to similar outputs

Is there a efficient way of approaching this particular problem in matlab.
I am trying to map this matrix or possible array BeansRice (see below)
Beans={0:1,0:1,0:2,0:2,0:2,0:2,0:1,0:1,0:2,0:2}
[a b c d e f g h i j ] = ndgrid(Beans{:})
BeansRice = [a(:) b(:) c(:) d(:) e(:) f(:) g(:) h(:) i(:) j(:)]
into a matrix/array BR (see below)
BR=[abc, de, fg, hij];
where if columns a, b and c each have values 0 (ties preference), I have preference for c>b>a. If all columns a, b and c each have values 1 (ties no preference), BR(1)=1. If columns a and b have values 0 and column c has value 2, BR(1)=2. If columns a and b have values 1 and column c has value 2, BR(1)=1.
I have an if function with indexing but I was thinking if it is possible to improve it, using the rank/order of the values in the matrix to break ties. Looking for a more efficient process as this is only a sub of a large problem.
You can use logical indexing instead of if conditions. For example
BR1(a==1 & b==1 & c==1)=1
BR1(a==0 & b==0 & c==2)=2
BR1(a==1 & b==1 & c==2)=1
...
then process the other parts, BR2(d==... & e>...)=##, then concatenate to obtain what you need
BR=[BR1(:) BR2(:) ...]
etc...