How to reshape vector into sqare matrix? - matlab

I have a vector of certain size and I want to reshape it into a square matrix. Here is an example: Let's say the vector is of size 784. Then I would create a matrix of size 28x28. In Matlab I would do it with the following command:
reshape(x,28,28)
Of course it can be possible that it is not possible to have an exact square matrix. In this case the matrix should as squarish as possible.
How can I do this calculation? That means how can I calculate the values a and b in reshape(x,a,b)?

Start with a equal to the square root of numel(x) rounded down. If that number doesn't divide numel(x), subtract 1 and try again. That way you end with a equal to the closest integer to sqrt(x) (from below) that divides numel(x). b would then be numel(x)/a, but you can simply use [] as the third argument to reshape:
a = floor(sqrt(numel(x)));
while mod(x,a)
a = a-1;
end
result = reshape(x,a,[]);
Example:
x = 1:20;
gives
result =
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20

One possible approach:
x = rand(1, 784);
divisors = find(rem(numel(x), 1:numel(x)) == 0);
[~, idx] = min(abs(divisors - sqrt(numel(x))));
x = reshape(x, divisors(idx), numel(x) / divisors(idx));
Let me explain:
Suppose you have a vector named x:
x = rand(1, 784);
First, you find the divisors of the size of x:
divisors = find(rem(numel(x), 1:numel(x)) == 0);
Then, you proceed to choose the divisor which is closest to the square root of x's size:
[~, idx] = min(abs(divisors - sqrt(numel(x))));
Finally, you reshape x using that divisor (and the corresponding multiple):
x = reshape(x, divisors(idx), numel(x) / divisors(idx));

It is not a simple problem to find closest factors of an integer. You need to use the MATLAB answers to the question Input an integer, find the two closest integers which, when multiplied, equal the input. From that question if you use the answer that provides the function findIntegerFactorsCloseToSquarRoot, you can use the following code to reshape.
[a, b] = findIntegerFactorsCloseToSquarRoot(numel(x));
reshape(x, a, b);

I suggest you to first check whether the number is prime or not by isprime(784).
Then you can use prime_factors = factor(784) to get the integer factorization of the number. (Depending on the MATLAB version you may use ifactor(784))
The rest needs just a little more work on prime_factors.

Related

How to create an Octave function that evaluate the sum of pairs of numbers in the vector?

It's like a reverse version of Pascal's triangle.
I want to create a vector-input function named
y = lastnum(vect) on Octave, that evaluate the sum of each pair of numbers in any vectors to output the single number from the evaluation loops like this
0 1 2 3 4
1 3 5 7
4 8 12
12 20
32
And the input and output would be like this,
lastnum([0 1 2 3 4])
ans = 32
I mean... is there any progresses that I can do??? You may not understand but, the reverse triangle above can guide you about my question.
I also tagged MATLAB since it has similar language. MATLAB pros may help my problem.
Notice that the number of times each element gets added to produce the final result comes from Pascals triangle itself, so, e.g., for the vector [a b c d] the result will be a+3b+3c+d. So create a vector of entries in Pascals triangle and multiply and add with the original vector v.
I only have access to Matlab, Octave may not have all these functions.
This is a one-liner diag(fliplr(pascal(numel(v)))).'*v(:).
Or a looping version
s = 0;
for i = 0:numel(v)-1
s = s+nchoosek(numel(v)-1,i)*v(i+1);
end
s
Simplest thing I can think of is:
while length(x) > 0
disp(x)
x = x(1:end-1) + x(2:end);
end
or did I misunderstand the question?
Here is the version for both MATLAB and Octave:
function y = lastnum(v)
while 1
if length(v) == 2
y = sum(v)
break;
end
# disp(v); # if you want to print the progress
vt = [];
for k = 1:(length(v)-1)
vt(end+1) = sum(v(k:(k+1)));
end
v = vt;
end
end

Average matrices in a cell array within a structure Matlab

In Matlab I have a structure AVG of size 1 x 6 which has one field averageNEST that is a cell array also of size 1 x 6.
Each averageNEST contains matrices of varying sizes (in one dimension), so for example
AVG(1).averageNEST{1,1} is of size 281 x 3 x 19 and
AVG(1).averageNEST{1,2} is of size 231 x 3 x 19
The 2nd and 3rd dimensions of the matrices are always 3 and 19, it is only the first dimension that can change.
I want to average over all the matrices contained within AVG(1).averageNEST and obtain one matrix of size X x 3 x 19 where X is the size of the smallest matrix in AVG(1).averageNEST.
Then I want to do this for all 6 averageNEST in AVG - so have a separate averaged matrix for AVG(1), AVG(2) ... AVG(6).
I have tried multiple things including trying to concatenate matrices using the following code:
for i=1:6
min_epoch = epoch + 1;
for ii=1:19
averageNEST(:,:,ii) = [AVG(i).averageNEST(1:min_epoch,:,ii)];
end
end
and then average this but it doesn't work and now I'm really confused about what I'm doing!
Can anyone help?
I am not sure if I understand what you want to do. If you want to keep only the elements up to the size of the the smallest matrix and then average those matrices you can do the following:
averageNEST = cell(size(AVG));
for iAVG = 1:numel(AVG)
nests = AVG(iAVG).averageNEST;
minsize = min(cellfun(#(x) size(x,1), nests));
reducednests = cellfun(#(y) y(1:minsize, :, :), nests, 'UniformOutput', false);
averageNEST{iAVG} = sum(cat(4, reducednests{:}), 4) / numel(nests);
end

Multiply values of every row in matrix with columnvector and sum rows up

We've got a columnvector m x 1 and a matrix m x n.
For the value in row i in the columnvector we want to multiply this value with each value in the same row i of the matrix, and then sum all of these up. This is to be repeated for every row i in the vector so that we end up with a columnvector.
Want to do this with a for-loop, have this so far (where M is the matrix and v is the initial columnvector we start out with) which returns an error that says "Subscripted assignment dimension mismatch.", so I guess I messed up with my indices somehow:
for i = 1:nv
for k = 1:mM
columnvectorendresult(i,) = columnvectorendresult(i,) + v(i,:)*M(i,:);
end
end
Don't know if I'm close with what I have so far, but not fully into this just yet. Any suggestions?
In case you want to sum after multiplication, the answer of knedlsepp using the distributive property of multiplication is the logical choice. If you want to use other operations than sums or differences, than the following answer can be applied more generically
Here we go:
%// columnvector m x 1
a = randi(5,3,1)
%// matrix m x n
B = randi(5,3,2)
%// multiplication
Ba = bsxfun(#times,B,a(:))
%// sum
BaSum = sum(Ba,2)
Example:
a =
3
4
4
B =
2 5
3 1
1 1
Ba =
6 15
12 4
4 4
BaSum =
21
16
8
Instead of multiplying each entry with the same factor and then doing the summation, you should sum the rows of the matrix first and then do the multiplication. ("Use the distributive property of multiplication.")
This is how you do this in MATLAB:
columnvectorendresult = v.*sum(M,2);

Graphing Polynomials in MATLAB

I need to create a polynomial of the form:
P(x) = q(1,1) + q(2,2)(x-z(1)) + q(3,3)(x-z(1))(x-z(2)) + --- + q(2n, 2n)(x-z(1))(x-z(2))...(x-z(2n)) NOTE: The indices of the equation have been shifted to accomodate MATLAB.
in MATLAB. Consult this link here specifically slides 15 and 16.
I have the matrix Q filled, so I have the diagonal, and I also have z(1:2n) filled.
I'm having a hard time figuring out a way to create a polynomial that I can graph this polynomial. I've tried to use a for loop to append each term to P(x), but it doesn't operate the way I thought it would.
So far, my code will calculate the coefficients (presented as Q(0,0) -> Q(2n+1, 2n+1) in the problem above) without a problem.
I'm having an issue with the construction of a degree n polynomial of the form described above. Plotting makes more sense now, create a vector x with evaluative values, and then run them through the polynomial "function" and plot the x vector against the resulting vector.
So I just need to create this polynomial.
I would use diag and cumprod to help you accomplish this. First use diag to extract the diagonals of your matrix Q. After, use cumprod to generate a vector of cumulative products.
How cumprod works on a vector is that for each element in the vector, the i'th element collects products from 1 up to the i'th element. As an example, if we had a vector V = [1 2 3 4 5], cumprod(V) would produce [1 2 6 24 120]. The 4th element (as an example) would be 1*2*3*4, representing the products from the 1st to the 4th element.
As such, this is the code that I would do:
qdiag = diag(Q);
xMinusZ = x - z; % Takes z and does x - z for every element in z
cumProdRes = cumprod(xMinusZ);
P = sum(qdiag .* [1;cumProdRes(1:end-1)]);
P should give you P(x) that you desired. Make sure that z is a column vector to make it compatible with the diagonals extracted from Q.
NB: I believe there is a typo in your equation. The last term of your equation (going with your convention) should have (x-z(2n-1)) and not (x-z(2n)). This is because the first term in your equation does not have z.
Here's an example. Let's suppose Q is defined
Q = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16];
The vector z is:
z = [4;3;2;1];
Let's evaluate the function at x = 2
Extracting the diagonals of Q should give us Q = [1;6;11;16]. Subtract x from every element of z should give us:
xMinusZ = [-2;-1;0;1];
Using the equation that you have above, we have:
P = 1 + 6*(-2) + 11*(-2)*(-1) + 16*(-2)*(-1)*(0) = 11
This is what the code should give.
What if we want to do this for more than one value of x?
As you have stated in your post, you want to evaluate this for a series of x values. As such, you need to modify the code so that it looks like this (make sure that x is a column vector):
qdiag = diag(Q);
xMinusZ = repmat(x,1,length(z)) - repmat(z',length(z),1);
cumProdRes = cumprod(xMinusZ,2);
P = sum(repmat(qdiag',length(z),1).*[ones(length(z),1) cumProdRes(:,1:end-1)],2);
P should now give you a vector of outputs, and so if you want to plot this, simply do plot(x,P);

Find extremum of multidimensional matrix in matlab

I am trying to find the Extremum of a 3-dim matrix along the 2nd dimension.
I started with
[~,index] = max(abs(mat),[],2), but I don't know how to advance from here. How is the index vector to be used together with the original matrix. Or is there a completely different solution to this problem?
To illustrate the task assume the following matrix:
mat(:,:,1) =
23 8 -4
-1 -26 46
mat(:,:,2) =
5 -27 12
2 -1 18
mat(:,:,3) =
-10 49 39
-13 -46 41
mat(:,:,4) =
30 -24 18
-40 -16 -36
The expected result would then be
ext(:,:,1) =
23
-46
ext(:,:,2) =
-27
18
ext(:,:,3) =
49
-46
ext(:,:,4) =
30
-40
I don't know how to use the index vector with mat to get the desired result ext.
1) If you want to find a maximum just along, let's say, 2d dimension, your variable index will be a matrix having dimensions (N,1,M), where N and M are number of elements of your matrix in the first and third dimensions respectively. In order to remove dummy dimensions, there is function squeeze() exist: index=squeeze(index) After that size(index) gives N,M
2) Depending on your problem, you probably need matlab function ind2sub(). First, you take a slice of your matrix, than find its maximum with linear indexing, and than you can restore your indicies with int2sub(). Here is an example for a 2D matrix:
M = randn(5,5);
[C,I] = max(M(:));
[index1,index2] = ind2sub(size(M),I);
Same method allows to find the absolute maximal element in whole 3D matrix.
Use ndgrid to generate the values along dimensions 1 and 3, and then sub2ind to combine the three indices into a linear index:
[~, jj] = max(abs(mat),[],2); %// jj: returned by max
[ii, ~, kk] = ndgrid(1:size(mat,1),1,1:size(mat,3)); %// ii, kk: all combinations
result = mat(sub2ind(size(mat), ii, jj, kk));
A fancier, one-line alternative:
result = max(complex(mat),[],2);
This works because, acccording to max documentation,
For complex input A, max returns the complex number with the largest complex modulus (magnitude), computed with max(abs(A)).