I have this piece of code and I am trying to optimize it using cache coherence method like temporal and spatial locality with cache blocking. (https://www.intel.com/content/www/us/en/developer/articles/technical/cache-blocking-techniques.html)
void randFunction1(int *arrayb, int dimension)
{
int i, j;
for (i = 0; i < dimension; ++i)
for (j = 0; j < dimension; ++j) {
arrayb[j * dimension+ i] = arrayb[j * dimension+ i] || arrayb[i * dimension+ j];
}
}
This is how I have optimised it but I was told it doesn't seem to make use of the memory blocking techniques.
for (int i = 0; i < dimension; ++i){
int j = i;
for (; j < dimension; ++j)
{
//access 2 times
arrayb[j * dimension+ i] = arrayb[j * dimension+ i] || arrayb[i * dimension+ j];
arrayb[i * dimension+ j] = arrayb[i * dimension+ j] || arrayb[j * dimension + i];
}
}
Could someone tell me how I can make use of the cache blocking (using locality for smaller tiles) for this sample piece of code? Any help is appreciated thank you!
I think you have a fundamental misunderstanding of cache blocking, misunderstood what you were being asked to do, or whoever asked you to do it doesn't understand. I am also hesitant to give you the full answer because this smells of a contrived example for a home work problem.
The idea is to block/tile/window up the data you're operating on, so the data you're operating on stays in the cache as you operate on it. To do this effectively you need to know the size of the cache and the size of the objects. You didn't give us enough details to know these answers but I can make some assumptions to illustrate how you might do this with the above code.
First how arrays are laid out in memory just so we can reference it later. Say dimension is 3.
That means we have a grid layout where i is the first number and j is the second like...
[0,0][0,1][0,2]
[1,0][1,1][1,2]
[2,0][2,1][2,2]
which is really in memory like:
[0,0][0,1][0,2][1,0][1,1][1,2][2,0][2,1][2,2]
We can also treat this like a 1d array where:
[0,0][0,1][0,2][1,0][1,1][1,2][2,0][2,1][2,2]
[ 0 ][ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ][ 7 ][ 8 ]
If our cache line could hold say 3 of these guys in there then there would be 3 'blocks'. 0-2, 3-5, and 6-8. If we access them in order, blocking just happens (assuming correct byte alignment of index 0 of the array... but lets keep it simple for now - this is likely taken care of already anyway). That is when we access 0, then 0, 1 and 2 are loaded into the cache. Next we access 1, it's already there. Then 2, already there. Then 3, load 3, 4 and 5 into the cache and so on.
Let's take a look at the original code for a second.
arrayb[j * dimension+ i] = arrayb[j * dimension+ i] || arrayb[i * dimension+ j];
Lets do just a couple of iterations but take out the indexing variables and replace them with their values. I'll use ^ to point to indexes you access and | to show the locations of our imaginary cache lines.
arrayb[0] = arrayb[0] || arrayb[0]
[ 0 ][ 1 ][ 2 ] | [ 3 ][ 4 ][ 5 ] | [ 6 ][ 7 ][ 8 ]
^
arrayb[3] = arrayb[3] || arrayb[1]
[ 0 ][ 1 ][ 2 ] | [ 3 ][ 4 ][ 5 ] | [ 6 ][ 7 ][ 8 ]
^ ^
arrayb[6] = arrayb[6] || arrayb[2]
[ 0 ][ 1 ][ 2 ] | [ 3 ][ 4 ][ 5 ] | [ 6 ][ 7 ][ 8 ]
^ ^
arrayb[1] = arrayb[1] || arrayb[3]
[ 0 ][ 1 ][ 2 ] | [ 3 ][ 4 ][ 5 ] | [ 6 ][ 7 ][ 8 ]
^ ^
So you see other than the first iteration, you cross the cache line every time jumping all over the place.
I think you noticed that the operation you're performing is logical or. That means you do not have to preserve the original order of operations as you go through the loop as your answer will be the same. That is it doesn't matter if you do arrayb[1] = arrayb[1] || arrayb[3] first or arrayb[3] = arrayb[3] | arrayb[1] first.
In your proposed solution you might think you're doing a little better because you noticed the pattern where on the second and fourth iteration we access the same indexes (just flip where we're reading and writing) but you didn't adjust the loops at all, so actually you just did twice the work.
0 = 0 || 0
0 = 0 || 0
3 = 3 || 1
1 = 1 || 3
6 = 6 || 2
2 = 2 || 6
1 = 1 || 3
3 = 3 || 1
4 = 4 || 4
4 = 4 || 4
7 = 7 || 5
5 = 5 || 7
2 = 2 || 6
6 = 6 || 2
5 = 5 || 7
7 = 7 || 5
8 = 8 || 8
8 = 8 || 8
If you fix the double work, you're on your way but you're not really using a blocking strategy. And to be honest, you can't. It's almost like the problem was designed to be not-real-world and purposely cause caching problems. The problem with your example is that you're using a single array that only accesses the same memory locations in pairs (twice). Other than their swap, they're never reused.
You can kind of optimize some of the accesses but you'll always be stuck with a majority collection that crosses boundaries. I think this is what you've been asked to do, but this is not a very good example problem for it. If we keep in mind how the memory in your array is actually being accessed and never really reused then increasing the size of the example makes it really obvious.
Say dimensions was 8 and your cache is big enough to hold 16 items (x86_64 can hold 16 ints in a cacheline). Then the most optimal access grouping would be operations where all indexes fell within 0-15, 16-31, 32-47, or 48-63. There aren't that many of them.
Not crossing a cache line:
0 = 0 || 0
1 = 1 || 8
8 = 8 || 1
9 = 9 || 9
18 = 18 || 18
19 = 19 || 26
26 = 26 || 19
27 = 27 || 27
36 = 36 || 36
37 = 37 || 44
44 = 44 || 37
54 = 54 || 54
55 = 55 || 62
62 = 62 || 55
63 = 63 || 63
Always crossing a cache line:
2 = 2 || 16
3 = 3 || 24
4 = 4 || 32
5 = 5 || 40
6 = 6 || 48
7 = 7 || 56
10 = 10 || 17
11 = 11 || 25
12 = 12 || 33
13 = 13 || 41
14 = 14 || 49
15 = 15 || 57
16 = 16 || 2
17 = 17 || 10
20 = 20 || 34
21 = 21 || 42
22 = 22 || 50
23 = 23 || 58
24 = 24 || 3
25 = 25 || 11
28 = 28 || 35
29 = 29 || 43
30 = 30 || 51
31 = 31 || 59
32 = 32 || 4
33 = 33 || 12
34 = 34 || 20
35 = 35 || 28
38 = 38 || 52
39 = 39 || 60
40 = 40 || 5
41 = 41 || 13
42 = 42 || 21
43 = 43 || 29
45 = 45 || 45
46 = 46 || 53
47 = 47 || 61
48 = 48 || 6
49 = 49 || 14
50 = 50 || 22
51 = 51 || 30
52 = 52 || 38
53 = 53 || 46
56 = 56 || 7
57 = 57 || 15
58 = 58 || 23
59 = 59 || 31
60 = 60 || 39
61 = 61 || 47
This really gets terrible as the number of items out paces the number that'll fit in the cache. You're only hope to save anything at this point is the pattern you noticed where you can do half the memory accesses that while smart, is not blocking/tiling.
The link you provided is similarly bad imo for illustrating cache blocking. It doesn't do a good job of describing what is actually taking place in its loops but at least it tries.
They tile the inner loop to keep memory accesses more local, which I think is what you've been asked to do but given a problem it can't apply to.
It smells like your teacher meant to give you 2 or 3 arrays, but accidentally gave you just one. It's very close to matrix multiplication but missing an inner loop and two other arrays.
Related
I am trying to learn awk by solving code puzzles. I am trying to read several "grids" of integers (representing bingo boards as per https://adventofcode.com/2021/day/4) into a three-dimensional awk array. An example "grid" can look like this:
22 13 17 11 0
8 2 23 4 24
21 9 14 16 7
6 10 3 18 5
1 12 20 15 19
And there are several of these in a longer input file. After reading each line into an array rows I am attempting to organize the numbers into this multi dimensional array called boards. Here is my example code:
{
b = 0
for (i in rows) {
split(rows[i], nums, " ")
for (j in nums) {
r = i % 5
n = j - 1
boards[b][r][n] = nums[j]
print b, r, n, nums[j], boards[b][r][n]
}
if (i%5==0)
++b
}
print boards[0][1][1]
}
Notice the debug printout print b, r, n, nums[j], boards[b][r][n] which indeed outputs the correct values for boards[b][r][n] on that row:
0 0 0 22 22
0 0 1 13 13
0 0 2 17 17
Etc. This seems to verify that the multi dimensional array gets written properly. Yet on the final line of the example code, the output is instead empty. I have tried using the form boards[b, r, n] for the array as well with the exact same result. Obviously there's something I'm not quite understanding here. Any help is appreciated. Full code for reproducibility:
# === ex.txt ===
7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1
22 13 17 11 0
8 2 23 4 24
21 9 14 16 7
6 10 3 18 5
1 12 20 15 19
3 15 0 2 22
9 18 13 17 5
19 8 7 25 23
20 11 10 24 4
14 21 16 12 6
14 21 17 24 4
10 16 15 9 19
18 8 23 26 20
22 11 13 6 5
2 0 12 3 7
# === solve.awk ===
BEGIN {
r = 0
}
{
if (NR == 1)
split($0, draws, "")
else if (NR != 2 && (NR-3)%6 != 5)
rows[r++] = $0
}
END {
b = 0
for (i in rows) {
split(rows[i], nums, " ")
for (j in nums) {
r = i % 5
n = j - 1
boards[b][r][n] = nums[j]
print b, r, n, nums[j], boards[b][r][n]
}
if (i%5==0)
++b
}
print boards[0][1][1]
}
I run this with awk -f solve.awk ex.txt. awk --version outputs GNU Awk 5.1.1, API: 3.1 (GNU MPFR 4.1.0-p13, GNU MP 6.2.1) as its first line. Thank you!
You are incrementing b at the end of the first iteration of your for (i in rows) loop because i == 0 ==> i%5 == 0, while you want to do it at the end of the 5th iteration. Try if (i%5 == 4) ++b.
Note that as you use GNU awk you could simplify all this. When the record separator (RS) is the empty string the records are separated by empty lines (one record per board):
$ awk -v RS='' '
NR>1 {
a[NR-2][1]; split($0, a[NR-2]);
}
END {
for(b in a) for(r in a[b])
boards[b][int((r-1)/5)][(r-1)%5] = a[b][r];
for(b in boards) for(r in boards[b]) for(n in boards[b][r])
print b, r, n, boards[b][r][n]
}' ex.txt
0 0 0 22
0 0 1 13
0 0 2 17
0 0 3 11
0 0 4 0
0 1 0 8
...
I would like to construct a function
[B, ind] = extract_ones(A)
which removes some sub-arrays from a binary array A in arbitrary dimensions, such that the remaining array B is the largest possible array with only 1's, and I also would like to record in ind that where each of the 1's in B comes from.
Example 1
Assume A is a 2-D array as shown
A =
1 1 0 0 0 1
1 1 1 0 1 1
0 0 0 1 0 1
1 1 0 1 0 1
1 1 0 1 0 1
1 1 1 1 1 1
After removing A(3,:) and A(:,3:5), we have the output B
B =
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
which is the largest array with only ones by removing rows and columns of A.
As the fifteen 1's of B corresponds to
A(1,1) A(1,2) A(1,6)
A(2,1) A(2,2) A(2,6)
A(4,1) A(4,2) A(4,6)
A(5,1) A(5,2) A(5,6)
A(6,1) A(6,2) A(6,6)
respectively, or equivalently
A(1) A(7) A(31)
A(2) A(8) A(32)
A(4) A(10) A(34)
A(5) A(11) A(35)
A(6) A(12) A(36)
so, the output ind looks like (of course ind's shape does not matter):
ind = [1 2 4 5 6 7 8 10 11 12 31 32 34 35 36]
Example 2
If the input A is constructed by
A = ones(6,3,4,3);
A(2,2,2,2) = 0;
A(4,1,3,3) = 0;
A(1,1,4,2) = 0;
A(1,1,4,1) = 0;
Then, by deleting the minimum cuboids containing A(2,2,2,2), A(4,1,3,3), A(1,1,4,3) and A(1,1,4,1), i.e. after deleting these entries
A(2,:,:,:)
A(:,1,:,:)
Then the remaining array B will be composed by 1's only. And the ones in B corresponds to
A([1,3:6],2:3,1:4,1:3)
So, the output ind lists the subscripts transformed into indices, i.e.
ind = [7 9 10 11 12 13 15 16 17 18 25 27 28 29 30 31 33 34 35 36 43 45 46 47 48 49 51 52 53 54 61 63 64 65 66 67 69 70 71 72 79 81 82 83 84 85 87 88 89 90 97 99 100 101 102 103 105 106 107 108 115 117 118 119 120 121 123 124 125 126 133 135 136 137 138 139 141 142 143 144 151 153 154 155 156 157 159 160 161 162 169 171 172 173 174 175 177 178 179 180 187 189 190 191 192 193 195 196 197 198 205 207 208 209 210 211 213 214 215 216]
As the array needed to be processed as above is in 8-D, and it should be processed more than once, so can anyone give me opinions on how to composing the program doing this task fast?
My work so far [Added at 2 am (GMT-4), 2nd Aug 2017]
My idea was that I delete the sub-arrays with the largest proportion of zero one by one. And here is my work so far:
Inds = reshape(1:numel(A),size(A)); % Keep track on which 1's survive.
cont = true;
while cont
sz = size(A);
zero_percentage = 0;
Test_location = [];
% This nested for loops are for determining which sub-array of A has the
% maximum proportion of zeros.
for J = 1 : ndims(A)
for K = 1 : sz(J)
% Location is in the form of (_,_,_,...,_)
% where the J-th blank is K, the other blanks are colons.
Location = strcat('(',repmat(':,',1,(J-1)),int2str(K),repmat(',:',1,(ndims(A)-J)),')');
Test_array = eval(strcat('A',Location,';'));
N = numel(Test_array);
while numel(Test_array) ~= 1
Test_array = sum(Test_array);
end
test_zero_percentage = 1 - (Test_array/N);
if test_zero_percentage > zero_percentage
zero_percentage = test_zero_percentage;
Test_location = Location;
end
end
end
% Delete the array with maximum proportion of zeros
eval(strcat('A',Test_location,'= [];'))
eval(strcat('Inds',Test_location,'= [];'))
% Determine if there are still zeros in A. If there are, continue the while loop.
cont = A;
while numel(cont) ~= 1
cont = prod(cont);
end
cont = ~logical(cont);
end
But I encountered two problems:
1) It may be not efficient to check all arrays in all sub-dimensions one-by-one.
2) The result does not contain the most number of rectangular ones. for example, I tested my work using a 2-dimensional binary array A
A =
0 0 0 1 1 0
0 1 1 0 1 1
1 0 1 1 1 1
1 0 0 1 1 1
0 1 1 0 1 1
0 1 0 0 1 1
1 0 0 0 1 1
1 0 0 0 0 0
It should return me the result as
B =
1 1
1 1
1 1
1 1
1 1
1 1
Inds =
34 42
35 43
36 44
37 45
38 46
39 47
But, instead, the code returned me this:
B =
1 1 1
1 1 1
1 1 1
Inds =
10 34 42
13 37 45
14 38 46
*My work so far 2 [Added at 12noon (GMT-4), 2nd Aug 2017]
Here is my current amendment. This may not provide the best result.
This may give a fairly OK approximation to the problem, and this does not give empty Inds. But I am still hoping that there is a better solution.
function [B, Inds] = Finding_ones(A)
Inds = reshape(1:numel(A),size(A)); % Keep track on which 1's survive.
sz0 = size(A);
cont = true;
while cont
sz = size(A);
zero_percentage = 0;
Test_location = [];
% This nested for loops are for determining which sub-array of A has the
% maximum proportion of zeros.
for J = 1 : ndims(A)
for K = 1 : sz(J)
% Location is in the form of (_,_,_,...,_)
% where the J-th blank is K, the other blanks are colons.
Location = strcat('(',repmat(':,',1,(J-1)),int2str(K),repmat(',:',1,(ndims(A)-J)),')');
Test_array = eval(strcat('A',Location,';'));
N = numel(Test_array);
Test_array = sum(Test_array(:));
test_zero_percentage = 1 - (Test_array/N);
if test_zero_percentage > zero_percentage
eval(strcat('Testfornumel = numel(A',Location,');'))
if Testfornumel < numel(A) % Preventing the A from being empty
zero_percentage = test_zero_percentage;
Test_location = Location;
end
end
end
end
% Delete the array with maximum proportion of zeros
eval(strcat('A',Test_location,'= [];'))
eval(strcat('Inds',Test_location,'= [];'))
% Determine if there are still zeros in A. If there are, continue the while loop.
cont = A;
while numel(cont) ~= 1
cont = prod(cont);
end
cont = ~logical(cont);
end
B = A;
% command = 'i1, i2, ... ,in'
% here, n is the number of dimansion of A.
command = 'i1';
for J = 2 : length(sz0)
command = strcat(command,',i',int2str(J));
end
Inds = reshape(Inds,numel(Inds),1); %#ok<NASGU>
eval(strcat('[',command,'] = ind2sub(sz0,Inds);'))
% Reform Inds into a 2-D matrix, which each column indicate the location of
% the 1 originated from A.
Inds = squeeze(eval(strcat('[',command,']')));
Inds = reshape(Inds',length(sz0),numel(Inds)/length(sz0));
end
It seems a difficult problem to solve, since the order of deletion can change a lot in the final result. If in your first example you start with deleting all the columns that contain a 0, you don't end up with the desired result.
The code below removes the row or column with the most zeros and keeps going until it's only ones. It keeps track of the rows and columns that are deleted to find the indexes of the remaining ones.
function [B,ind] = extract_ones( A )
if ~islogical(A),A=(A==1);end
if ~any(A(:)),B=[];ind=[];return,end
B=A;cdel=[];rdel=[];
while ~all(B(:))
[I,J] = ind2sub(size(B),find(B==0));
ih=histcounts(I,[0.5:1:size(B,1)+0.5]); %zero's in rows
jh=histcounts(J,[0.5:1:size(B,2)+0.5]); %zero's in columns
if max(ih)>max(jh)
idxr=find(ih==max(ih),1,'first');
B(idxr,:)=[];
%store deletion
rdel(end+1)=idxr+sum(rdel<=idxr);
elseif max(ih)==max(jh)
idxr=find(ih==max(ih),1,'first');
idxc=find(jh==max(jh),1,'first');
B(idxr,:)=[];
B(:,idxc)=[];
%store deletions
rdel(end+1)=idxr+sum(rdel<=idxr);
cdel(end+1)=idxc+sum(cdel<=idxc);
else
idxc=find(jh==max(jh),1,'first');
B(:,idxc)=[];
%store deletions
cdel(end+1)=idxc+sum(cdel<=idxc);
end
end
A(rdel,:)=0;
A(:,cdel)=0;
ind=find(A);
Second try: Start with a seed point and try to grow the matrix in all dimensions. The result is the start and finish point in the matrix.
function [ res ] = seed_grow( A )
if ~islogical(A),A=(A==1);end
if ~any(A(:)),res={};end
go = true;
dims=size(A);
ind = cell([1 length(dims)]); %cell to store find results
seeds=A;maxmat=0;
while go %main loop to remove all posible seeds
[ind{:}]=find(seeds,1,'first');
S = [ind{:}]; %the seed
St = [ind{:}]; %the end of the seed
go2=true;
val_dims=1:length(dims);
while go2 %loop to grow each dimension
D=1;
while D<=length(val_dims) %add one to each dimension
St(val_dims(D))=St(val_dims(D))+1;
I={};
for ct = 1:length(S),I{ct}=S(ct):St(ct);end %generate indices
if St(val_dims(D))>dims(val_dims(D))
res=false;%outside matrix
else
res=A(I{:});
end
if ~all(res(:)) %invalid addition to dimension
St(val_dims(D))=St(val_dims(D))-1; %undo
val_dims(D)=[]; D=D-1; %do not try again
if isempty(val_dims),go2=false;end %end of growth
end
D=D+1;
end
end
%evaluate the result
mat = prod((St+1)-S); %size of matrix
if mat>maxmat
res={S,St};
maxmat=mat;
end
%tried to expand, now remove seed option
for ct = 1:length(S),I{ct}=S(ct):St(ct);end %generate indices
seeds(I{:})=0;
if ~any(seeds),go=0;end
end
end
I tested it using your matrix:
A = [0 0 0 1 1 0
0 1 1 0 1 1
1 0 1 1 1 1
1 0 0 1 1 1
0 1 1 0 1 1
0 1 0 0 1 1
1 0 0 0 1 1
1 0 0 0 0 0];
[ res ] = seed_grow( A );
for ct = 1:length(res),I{ct}=res{1}(ct):res{2}(ct);end %generate indices
B=A(I{:});
idx = reshape(1:numel(A),size(A));
idx = idx(I{:});
And got the desired result:
B =
1 1
1 1
1 1
1 1
1 1
1 1
idx =
34 42
35 43
36 44
37 45
38 46
39 47
I am unable to figure out how to merge two arrays. My data is like this with arrays A and B.
A = [ 0 0; 0 0; 2 2; 2 2;]
B = [ 1 1; 1 1; 3 3; 3 3; 4 4; 4 4; 5 5; 5 5;]
and I need the final array "C" to look like this after merging:
C = [ 0 0; 0 0; 1 1; 1 1; 2 2; 2 2; 3 3; 3 3; 4 4; 4 4; 5 5; 5 5;]
I've tried using different ways with reshaping each array and trying to use a double loop but haven't got it to work yet.
In my actual data it is inserting 9 rows of array B following 3 rows of array A and then repeated 100 times. So, there are 12 new merged rows (3 rows from array A and 9 rows from array B) repeated 100 times with a final row number == 1200. Array A actual data has 300 rows and actual Array B data has 900 rows
thanks,
Here's a solution using only reshape:
A = [ 6 6; 3 3; 5 5; 4 4;]
B = [ 0 0; 21 21; 17 17; 33 33; 29 29; 82 82;]
A_count = 2;
B_count = 3;
w = size(A,2); %// width = number of columns
Ar = reshape(A,A_count,w,[]);
Br = reshape(B,B_count,w,[]);
Cr = [Ar;Br];
C = reshape(Cr,[],w)
The [] in reshape means "how ever many you need to get to the total number of elements". So if we have 12 elements in B and do:
Br = reshape(B,3,2,[]);
We're reshaping B into a 3x2xP 3-dimensional matrix. Since the total number of elements is 12, P = 2 because 12 = 3x2x2.
Output:
A =
6 6
3 3
5 5
4 4
B =
0 0
21 21
17 17
33 33
29 29
82 82
C =
6 6
3 3
0 0
21 21
17 17
5 5
4 4
33 33
29 29
82 82
Approach #1
This could be one approach assuming I got the requirements of the problem right -
%// Inputs
A = [ 6 6; 3 3; 5 5; 4 4;];
B = [ 0 0; 21 21; 17 17; 33 33; 29 29; 82 82;];
%// Parameters that decide at what intervals to "cut" A and B along the rows
A_cutlen = 2; %// Edit this to 3 for the actual data
B_cutlen = 3; %// Edit this to 9 for the actual data
%// Cut A and B along the rows at specified intervals into 3D arrays
A3d = permute(reshape(A,A_cutlen,size(A,1)/A_cutlen,[]),[1 3 2])
B3d = permute(reshape(B,B_cutlen,size(B,1)/B_cutlen,[]),[1 3 2])
%// Vertically concatenate those 3D arrays to get a 3D array
%// version of expected output, C
C3d = [A3d;B3d]
%// Convert the 3D array to a 2D array which is the final output
C_out = reshape(permute(C3d,[1 3 2]),size(C3d,1)*size(C3d,3),[])
Sample run -
A =
6 6
3 3
5 5
4 4
B =
0 0
21 21
17 17
33 33
29 29
82 82
A_cutlen =
2
B_cutlen =
3
C_out =
6 6
3 3
0 0
21 21
17 17
5 5
4 4
33 33
29 29
82 82
Approach #2
Just for the love of bsxfun, here's one approach with it and ones (no reshape or permute) -
%// Assuming A_cutlen and B_cutlen decide cutting intervals for A and B
%// Concatenate A and B along rows
AB = [A;B]
%// Find the row indices corresponding to rows from A and B to be placed
%// according to the problem requirements
idx1 = [1:A_cutlen size(A,1)+[1:B_cutlen]]
idx2 = [A_cutlen*ones(1,A_cutlen) B_cutlen*ones(1,B_cutlen)]
idx = bsxfun(#plus,idx1(:),idx2(:)*[0:size(A,1)/A_cutlen-1])
%// Re-arrange AB based on "idx" for the desired output
C = AB(idx,:)
based on your new criteria this is what you want. My solution isn't the nicest looking (maye someone can think of a nice vectorized approach), but it works
a_step = 2;
b_step = 3;
C = zeros(size([A;B]));
%we use two iterators, one for each matrix, they must be initialized to 1
a_idx = 1;
b_idx = 1;
%this goes through the entire c array doing a_step+b_step rows at a
%time
for c_idx=1:a_step+b_step :size(C,1)-1
%this takes the specified number of rows from a
a_part = A(a_idx:a_idx+a_step-1,:);
%tkaes the specified number of rows from b
b_part = B(b_idx:b_idx+b_step-1,:);
%combines the parts together in the appropriate spot in c
C(c_idx:c_idx + a_step + b_step -1,:) = [a_part;b_part];
%advances the "iterator" on the a and b matricies
a_idx = a_idx + a_step;
b_idx = b_idx + b_step;
end
using
A = [ 6 6; 3 3; 5 5; 4 4;]
B = [ 0 0; 21 21; 17 17; 33 33; 29 29; 82 82;]
produces
C =[6 6; 3 3; 0 0; 21 21; 17 17; 5 5; 4 4; 33 33; 29 29; 82 82;]
I have two large arrays which I will illustrate using the following examples.
The first array A is:
[ 1 21;
3 4;
4 12;
5 65 ];
The second array B is:
[ 1 26;
31 56;
4 121;
5 54 ];
I want to obtain the final array C as following:
[ 1 21 26;
4 12 121;
5 65 54];
i.e. use the common elements of first column from A and B to sieve out the rows I want to extract from arrays A and B and generate C.
Use the two-output vesion of ismember:
[ii jj] = ismember(A(:,1), B(:,1));
C = [ A(ii,:) B(jj(ii),2) ];
Note that in the second line ii is a logical index, whereas jj(ii) is a standard (integer) index.
bsxfun approach -
%// Slightly bigger and not-so-straightforward example to avoid any confusion
A =[ 1 21;
3 4;
4 12;
8 10
5 65]
B = [ 1 26;
31 56;
4 121;
5 54
9 99
8 88]
binmat = bsxfun(#eq,A(:,1),B(:,1).');%//'
[v1,v2] = max(binmat,[],2);
C = [A(any(binmat,2),:) B(nonzeros(v1.*v2),2:end)]
Output -
A =
1 21
3 4
4 12
8 10
5 65
B =
1 26
31 56
4 121
5 54
9 99
8 88
C =
1 21 26
4 12 121
8 10 88
5 65 54
I have a 2d array : grid[x][y]
1 2 3 4 5 6 7 8
11 12 13 14 15 16 17 18
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
41 42 43 44 45 46 47 48
Example:
I would like to move the 3rd column down, the bottom element goes into the first row like this:
41 2 3 4 5 6 7 8
1 12 13 14 15 16 17 18
11 22 23 24 25 26 27 28
21 32 33 34 35 36 37 38
31 42 43 44 45 46 47 48
I used the following function to move the whole array left and right but in 2d array this obviously doesn't work, because you have to move the element to another array if shifting it:
function wrap( t, l )
-- change i=0 to move left and i=1 to right
for i = 1, l do
table.insert( t, 1, table.remove( t, #t ) )
end
end
I tried this function in Lua scratchpad and it doesn't work...I can't figure out the logic without losing the element.
function shift( t, direction )
for i=1,#t do
if(direction == "left") then
if(i == 1) then
tempElement = t[#t][6]
else
tempElement = t[i-1][6]
end
else
if(i == 7) then
tempElement = t[1][6]
else
tempElement = t[i+1][6]
end
end
table.insert( t[i], 6, tempElement )
table.remove( t[i], 12)
end
end
How can I shift the elements to another column but same index, so grid[5][1] goes in grid[4][1] and so on.
According to your comments, you are trying to shift items within a column, example:
{{11,12,13},
{21,22,23},
{31,32,33}}
to
{{31,12,13},
{11,22,23},
{21,32,33}}
The following code uses your wrap function:
g={{11,12,13},{21,22,23},{31,32,33}}
function shifItemWithinRow( array, shift )
shift = shift or 1 -- make second arg optional, defaults to 1
for i = 1, shift do
table.insert( array, 1, table.remove( array, #array ) )
end
end
function shifItemWithinColumn( grid, columnID, shiftCount )
shiftCount = shiftCount or 1 -- make second arg optional, defaults to 1
-- copy all items from g into new table, shifted:
local numRows = #grid
local newCol = {}
for i=1,numRows do --
local newI = i+shiftCount
if newI > numRows then newI = newI - numRows end
if newI < 1 then newI = numRows - newI end
newCol[newI] = grid[i][columnID]
end
-- copy all items into grid
for i=1,numRows do -- # each row
grid[i][columnID] = newCol[i]
end
end
function printGrid(g)
for i, t in ipairs(g) do
print('{' .. table.concat(t, ',') .. '}')
end
end
printGrid(g)
shifItemWithinColumn(g, 1) -- shift col 1 by +1
print()
printGrid(g)
print()
shifItemWithinColumn(g, 1, -1) -- shift col 1 by -1
printGrid(g)
This example shifts a column by +1 then by -1 (so final is same as start).