I have a 221 x 24 cell array, S. Within each array is another array consisting of several different fields (let's just say A, B, C, and D), whereby each field (A, B, C, D) are a 50 x 50 array. I want to sum only the A's, B's, C's, and D's within each column of array S. For example:
S{1,1}.A + S{2,1}.A + ... + S{23,1}.A ...
S{1,2}.B + S{2,2}.B + ... + S{153,2}.B ...
S{111,3}.C + S{117,3}.C + ... + S{230,3}.C ...
What is the simplest way to do this? I know there is a function to sum if there are no fields within the structure (e.g., sum([S{:}]) ), but I only want the specific fields in each summed. Any thoughts?
There is likely more "MATLABy" way of avoiding loops and making this even simpler, but this loop should be reasonably straightforward:
FN = fieldnames(S{1});
for i = 1 : size(S, 1)
sumStruct{i} = 0;
for j = 1 : size(S, 2)
sumStruct{i} = sumStruct{i} + S{i,j}.(FN{j});
end
end
This assumes you want sum of all S{1...N, 1}.A, S{1...N, 2}.B and so on, as it appears in the question. If you want S{1...N, 1}.B too you need 3rd loop and 2 indices for sumStruct - it should be relatively straightforward to implement.
Related
I have a set of data points, which are complex numbers which have, let’s say, 8 rows and 6 columns. If you look at the program, you can see that data sets are arranged very randomly. 1st, 2nd, 3rd columns are okay, but 4th column, is bit anomalous. What I mean to say is that after element at B(5, 4) (i.e. 25.9868674011374) it is coming 2.74257567017122 [B(6, 4)] instead of 26.8410063269595 which has gone to B(6, 6). I want that column arranged in ascending order (every sorting should be done for real part). Also, in the 5th column, even though the real parts ae arranged in ascending order, the imaginary part are kind of swapped. For example, after B(2,5) it should be B(3,6) not B(3,5). I have tried ‘sort’ command, but it not working as I want.
For the people who is wondering wht is the problem with sort, just try to run this command:
A = [1+2i 3+i i 0 -i]; Dreal= sort(real(A)); Dimg = sort(imag(A));D=[Dreal;Dimg];
What I want is -i, 0, i ,3+I,1+2i, what sort gives is something else.
Also, there may be instances where 4th, 5th and 6th column may behave ‘normally’, but 1st, 2nd, 3rd columns behaving erratically. So even if 4th, 5th and 6th columns are behaving ‘normally’ I want it to be sorted down in ascending order. Any way through this? By the by, I am using Matlab- 2015b. The code is:
clear all; clc;
B=[-2.14981736484179 + 0.00000000000000i,-1.38134547606946 + 0.00000000000000i,1.38451324569297 + 0.00000000000000i,22.5759136576435 + 0.00000000000000i,2.28536796878740 + 0.333911501246080i,2.28536796878740 - 0.333911501246080i;-2.22047322414157 + 0.00000000000000i,-1.43596350944258 + 0.00000000000000i,1.43889226552228 + 0.00000000000000i,23.4278498788255 + 0.00000000000000i,2.39484729461819 + 0.303429715954385i,2.39484729461819 - 0.303429715954385i;-2.29148887606605 + 0.00000000000000i,-1.49057388951113 + 0.00000000000000i,1.49328382360683 + 0.00000000000000i,24.2803021611395 + 0.00000000000000i,2.50423839041542 - 0.265225265037282i,2.50423839041542 + 0.265225265037282i;-2.36284412024645 + 0.00000000000000i,-1.54517861014711 + 0.00000000000000i,1.54768832224205 + 0.00000000000000i,25.1333019698605 + 0.00000000000000i,2.61351621914550 + 0.215386193278572i,2.61351621914550 - 0.215386193278572i;-2.43451884781340 + 0.00000000000000i,-1.59977935450756 + 0.00000000000000i,1.60210590260749 + 0.00000000000000i,25.9868674011374 + 0.00000000000000i,2.72266244928806 - 0.142395604889199i,2.72266244928806 + 0.142395604889199i;-2.50649346218904 + 0.00000000000000i,-1.65437753673930 + 0.00000000000000i,1.65653651325774 + 0.00000000000000i,2.74257567017122 + 0.00000000000000i,2.92075248853987 + 0.00000000000000i,26.8410063269595 + 0.00000000000000i;-2.57874914363635 + 0.00000000000000i,-1.70897433922564 + 0.00000000000000i,1.71097996266870 + 0.00000000000000i,2.74509085049068 + 0.00000000000000i,3.13593380433481 + 0.00000000000000i,27.6957188653678 + 0.00000000000000i;-2.65126800477853 + 0.00000000000000i,-1.76357074549849 + 0.00000000000000i,1.76543595943333 + 0.00000000000000i,2.78382099280761 + 0.00000000000000i,3.31458248082037 + 0.00000000000000i,28.5509993172157 + 0.00000000000000i];
k=1:1:4;
B1=sort(real(B));
B2=sort(imag(B));
B3=sort(B);
Thanks in advance.
You seem to be wanting the sort(A,'ComparisonMethod','real') feature available in Matlab r2017a, but for use in r2015b.
You can recreate the feature using the sortrows function:
clear
A = [1+2i 3+1i 1i 0 -1i];
AB = [real(A); imag(A)];
[~,I] = sortrows(AB');
Asort = A(I)
yields Asort = [0 - 1i 0 + 0i 0 + 1i 1 + 2i 3 + 1i]. sortrows sorts each row of an array first according to the first column, then breaks ties with the next column and so on until the whole array is sorted (Documentation here). The idea here is to make the first column the real component, and the second column the imaginary component.
For higher-dimensional arrays of complex numbers, you have a few options, but they'll all use the same principle as above. If you want to sort all elements of your matrix B, you can generate a sorted vector use the following code:
Bsep = [real(B(:)),imag(B(:))];
[~,I] = sortrows(Bsep);
SortedVec = B(I);
To reshape back into an 8x6 array (with sorted elements arranged down columns, from left to right), simply add this line:
Bsort = reshape(SortedVec,8,6);
Or, perhaps you want to sort each column of your array separately. Just use sortrows in a loop:
nCols = size(B,2);
Bsort = NaN(size(B));
for j = 1:nCols
Bsep = [real(B(:,j)),imag(B(:,j))];
[~,I] = sortrows(Bsep);
Bsort(:,j) = B(I,j);
end
If you instead want to sort by the imaginary part first, then break ties with the real part, all you need to do is switch the position of the calls to real and imag in any of the code snippets above. For example,
clear
A = [1+2i 3+1i 1i 0 -1i];
AB = [imag(A); real(A)]; % note that real and imag are switched
[~,I] = sortrows(AB');
Asort = A(I)
yields Asort = [0 - 1i 0 + 0i 0 + 1i 3 + 1i 1 + 2i]
I am looking for the formulas to find the memory location of an element in a 3-D Array for row major and for column major. After using my logic I end up with the following formulas.
say array is A[L][M][N].
row-major:Loc(A[i][j][k])=base+w(M*N(i-x)+N*(j-y)+(k-z))
column-major:Loc(A[i][j][k])=base+w(M*n(i-x)+M*(k-z)+(j-y))
where x, y, z are lower bounds of 1st(L) 2nd(M) and 3rd(N) index.
I tried this formula and got the correct result but when I applied this formula on a Question in the book then the answer did not match. Please can anyone help me out with this.
Formula for 3D Array
Row Major Order:
Address of
A[I, J, K] = B + W * [(D - Do)*RC + (I - Ro)*C + (J - Co)]
Column Major Order:
Address of
A[I, J, K] = B + W * [(D - Do)*RC + (I - Ro) + (J - Co)*R]
Where:
B = Base Address (start address)
W = Weight (storage size of one element stored in the array)
R = Row (total number of rows)
C = Column (total number of columns)
D = Width (total number of cells depth-wise)
Ro = Lower Bound of Row
Co = Lower Bound of Column
Do = Lower Bound of Width
Right one is:
row-major:Loc(A[i][j][k])=base+w(N*(i-x)+(j-y)+M*N(k-z))
column-major:Loc(A[i][j][k])=base+w((i-x)+M*N(k-z)+M*(j-y))
Thanks! #Vinay Yadav for your comment. As suggested by Vinay please visit the link to understand this in great detail: https://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays.
Keep this in mind and you never get it wrong:
Row Major: Lexicographical Order
Column Major: Co-lexicographical Order
If you don't know what Co-lexicographical and Lexicographical are: Check out this Wikipedia page for more. Let me highlight important part for you, do give it a read:
The words in a lexicon (the set of words used in some language) have a
conventional ordering, used in dictionaries and encyclopedias, that
depends on the underlying ordering of the alphabet of symbols used to
build the words. The lexicographical order is one way of formalizing
word order given the order of the underlying symbols.
The formal notion starts with a finite set A, often called the
alphabet, which is totally ordered. That is, for any two symbols a and
b in A that are not the same symbol, either a < b or b < a.
The words of A are the finite sequences of symbols from A, including
words of length 1 containing a single symbol, words of length 2 with 2
symbols, and so on, even including the empty sequence varepsilon with no symbols
at all. The lexicographical
order on the set of all these finite words orders the words as
follows:
Given two different words of the same length, say a = a1a2...ak and b
= b1b2...bk, the order of the two words depends on the alphabetic order of the symbols in the first place i where the two words differ
(counting from the beginning of the words): a < b if and only if ai <
bi in the underlying order of the alphabet A. If two words have
different lengths, the usual lexicographical order pads the shorter
one with "blanks" (a special symbol that is treated as smaller than
every element of A) at the end until the words are the same length,
and then the words are compared as in the previous case.
After this you can learn about Co-Lexicographical Order from the same Wikipedia page mentioned above. Above quoted part is taken directly from the Motivation and Definition titled part of the Wikipedia page mentioned above. Visit it once and you will have a better understanding of both.
You just need to find the Lexicographical and Co-Lexicographical position of (i, j, k) among all possible (foo1, foo2, foo3) in the array A of yours:
foo1 -> L possibilities: [Lower Bound x, Upper Bound x + L - 1]
foo2 -> M possibilities: [Lower Bound y, Upper Bound y + M - 1]
foo3 -> N possibilities: [Lower Bound z, Upper Bound z + N - 1]
Based on the this knowledge, you will get that:
1). Number of elements A[foo1][foo2][foo3] (foo1, foo2, foo3) present before element A[i][j][k] (i, j, k) in Row Major Order or Lexicographical Order are:
[ (i - x)*M*N + (j - y)*N + (k - z) ]
2). Number of elements A[foo1][foo2][foo3] (foo1, foo2, foo3) present before element A[i][j][k] (i, j, k) in Column Major Order or Co-lexicographical Order are:
[ (i - x) + (j - y)*L + (k - z)*L*M ]
Now, you can do the rest of your calculation where you bring in your base and W thing to get the final answer you need.
I'm writing a function that requires some values in a matrix of arbitrary dimansions to be dropped in a specified dimension.
For example, say I have a 3x3 matrix:
a=[1,2,3;4,5,6;7,8,9];
I might want to drop the third element in each row, in which case I could do
a = a(:,1:2)
But what if the dimensions of a are arbitrary, and the dimension to trim is defined as an argument in the function?
Using linear indexing, and some carefully considered maths is an option but I was wondering if there is a neater soltion?
For those interested, this is my current code:
...
% Find length in each dimension
sz = size(dat);
% Get the proportion to trim in each dimension
k = sz(d)*abs(p);
% Get the decimal part and integer parts of k
int_part = fix(k);
dec_part = abs(k - int_part);
% Sort the array
dat = sort(dat,d);
% Trim the array in dimension d
if (int_part ~=0)
switch d
case 1
dat = dat(int_part + 1 : sz(1) - int_part,:);
case 2
dat = dat(:,int_part + 1 : sz(2) - int_part);
end
end
...
It doesn't get any neater than this:
function A = trim(A, n, d)
%// Remove n-th slice of A in dimension d
%// n can be vector of indices. d needs to be scalar
sub = repmat({':'}, 1, ndims(A));
sub{d} = n;
A(sub{:}) = [];
This makes use of the not very well known fact that the string ':' can be used as an index. With due credit to this answer by #AndrewJanke, and to #chappjc for bringing it to my attention.
a = a(:, 1:end-1)
end, used as a matrix index, always refers to the index of the last element of that matrix
if you want to trim different dimensions, the simplest way is using and if/else block - as MatLab only supports 7 dimensions at most, you wont need an infinite number of these to cover all bases
The permute function allows to permute the dimension of an array of any dimension.
You can place the dimension you want to trim in a prescribed position (the first, I guess), trim, and finally restore the original ordering. In this way you can avoid running loops and do what you want compactly.
This question is related to matlab: find the index of common values at the same entry from two arrays.
Suppose that I have an 1000 by 10000 matrix that contains value 0,1,and 2. Each row are treated as a sample. I want to calculate the pairwise distance between those samples according to the formula d = 1-1/(2p)sum(a/c+b/d) where a,b,c,d can treated as as the row vector of length 10000 according to some definition and p=10000. c and d are probabilities such that c+d=1.
An example of how to find the values of a,b,c,d: suppose we want to find d between sample i and bj, then I look at row i and j.
If kth entry of row i and j has value 2 and 2, then a=2,b=0,c=1,d=0 (I guess I will assign 0/0=0 in this case).
If kth entry of row i and j has value 2 and 1 or vice versa, then a=1,b=0,c=3/4,d=1/4.
The similar assignment will give to the case for 2,0(a=0,b=0,c=1/2,d=1/2),1,1(a=1,b=1,c=1/2,d=1/2),1,0(a=0,b=1,c=1/4,d=3/4),0,0(a=0,b=2,c=0,d=1).
The matlab code I have so far is using for loops for i and j, then find the cases above by using find, then create two arrays for a/c and b/d. This is extremely slow, is there a way that I can improve the efficiency?
Edit: the distance d is the formula given in this paper on page 13.
Provided those coefficients are fixed, then I think I've successfully vectorised the distance function. Figuring out the formulae was fun. I flipped things around a bit to minimise division, and since I wasn't aware of pdist until #horchler's comment, you get it wrapped in loops with the constants factored out:
% m is the data
[n p] = size(m, 1);
distance = zeros(n);
for ii=1:n
for jj=ii+1:n
a = min(m(ii,:), m(jj,:));
b = 2 - max(m(ii,:), m(jj,:));
c = 4 ./ (m(ii,:) + m(jj,:));
c(c == Inf) = 0;
d = 1 - c;
distance(ii,jj) = sum(a.*c + b.*d);
% distance(jj,ii) = distance(ii,jj); % optional for the full matrix
end
end
distance = 1 - (1 / (2 * p)) * distance;
Suppose, I have an n-dimensional array of integers (for n=1 it's a vector, for n=2 it's a rectangular matrix, for n=3 it's a parallelepiped, etc). I need to reorder elements of the array so that elements in each row, column, etc are in a non-decreasing order.
Is it possible for any input array?
Is the required ordering unique for any input array? I just realized that the answer for this question in general is no, e.g. for square matrices.
Is the required ordering unique for any input array that has different lengths in all dimensions?
What is the fastest algorithm to produce the required ordering?
Is it possible for any input array?
Yes, if we will look on the array as a single dimension array, with the same number of elements, and then sort it, by traversing it back to the original n-dimensions array, it remains sorted, since for each i1,....,i_k,...,i_m: for all i_k < i_k':
i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k) + ... < i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k') + ...
Thus (the array is ordered):
arr[i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k) + ...] < arr[ i_1 + n1*i_2 + n2^2*i_3 + .... (n_k-1)^(k-1)(i_k') + ...]
Thus (back to original array):
arr[i_1][i_2]...[i_k]... < arr[i_1][i_2]...[i_k']...
As for the 2nd question:
Is the required ordering unique for any input array that has different
lengths in all dimensions?
No:
1 1 1 3
3 4 1 4
5 6 5 6
What is the fastest algorithm to produce the required ordering?
One solution is suggested already: regard it is a big long array and sort it.
Complexity is O(n_1*n_2*...*n_m*log(n_1*n_2*...*n_m))
My gut says if you could do it faster, you could sory faster then O(nlogn), but I have no proof for this claim, so it might be wrong.
Let me elaborate more about Alptigin Jalayr's idea.
Suppose we have rows sorted, so for the following data, we have a <= b and c <= d.
. .
..., a, ..., b, ...
. .
..., c, ..., d, ...
. .
When a is greater than c, i.e. c <a, then swap of them gives us c < b since a <= b, and a <=d since b <= d (if b > d, we swap b and d as well). In a word, sorting rows first and then columns next can give you the desired matrix.