Ordering of a 2D array - c

I am trying to solve a problem on 2D arrays and need little help. The problem goes like this:
Suppose we have a 2D array A of size nxn comprising of unique elements. The need to rearrange the elements of A as follows. Let A11, A12, A21, A22 be four mutually disjoint subarrays of A, each of size n/2 x n/2. Then A11 < A12 < A21 < A22. If each of these subarrays is recursively split into four equal-sized sub-arrays, then also the property holds.
User input: n, N (≥ n2). n is a power of 2
I have tried many things but nothing seems to work.

You need to create a function which will convert an index between 0 and n*n-1 to coordinates in your array according to the ordering in question. Then you just run some usual 1D sorting algorithm, on an array of size n*n, jth element of which is substituted using that function. It solves the problem.
Update: the mapping function maps numbers in this matrix to their coordinates:
0 1 4 5
2 3 6 7
8 9 12 13
10 11 14 15

Piggybacking somewhat on the answer of unkulunkulu I think you could approach it as follows:
Take all the values in your matrix (2D) and put them in a simple array (1D). Then take this array and sort the values from lowest to highest.
Now what you need to do is fill the matrix again but in such a way that it conforms to the rules you have specified. If you have a look at a Z-order space filling curve in 2D, you will find that if you fill you matrix in this order (with the sorted elements), that the resulting matrix has your desired properties.
Now actually coding this would be up to you.

The book numerical recipes chapter 21.8 http://www.nrbook.com/nr3/ gives an analytic expression to calculate an index into the 2D array given the coordinates of a quadtree.
Here is another straight forward approach that I tried, but I don't like it as much:
(defun quad-pos (pos)
"POS is a list of letters that indicate the position in a 2x2 matrix [a,b; c,d]."
(let ((x 0)
(y 0)
(s 1))
(dolist (e pos)
(setf s (/ s 2))
(ecase e
('a )
('b (incf x s))
('c (incf y s))
('d (incf x s) (incf y s))))
(values x y)))
#+nil
(quad-pos '(a)) ;=> 0, 0
#+nil
(quad-pos '(a b c)) ;=> 1/4, 1/8
#+nil
(quad-pos '(d d d d)) ;=> 15/16, 15/16

Related

Getting corresponding coordinates of a vectorized matrix

I have a matrix X of size n x m. I resized X to a vector a of length n x m.
How can I know "automatically" that the ith element in vector a corresponds to what element position (coordinates) in X?
I have written the following MATLAB code but I do not know how to continue.
X = rand(10,10);
[n,m] = size(X);
a = reshape(X, [n*m, 1]);
t = zeros(length(a),1);
for i = 1 : length(a)
t(i) = % I want to perform here the sum over the x and y coordinate values of the element in X
% that corresponds to the ith element in vector a.
end
Any help will be very appreciated.
That's what ind2sub does:
[row, col] = ind2sub([m n], i);
However, you may prefer to do it manually:
row = mod(i-1,m)+1;
col = floor((i-1)/m)+1;
This works because Matlab used column-major order for storing array elements. For example, in a 3×4 matrix the order in which the elements are stored in memory is as follows:
1 4 7 10
2 5 8 11
3 6 9 12
So the entry in the 2nd row, 3rd column is the 8th element in (column-major) linear order. When this matrix is reshaped into a vector (or into any other shape) this linear order is preserved. Therefore you can retrieve the original coordinates by divisions and modulus operations. Note also that, since Matlab's indexing is 1-based (as opposed to 0-based), the modulus operations need to be shifted by 1.

Finding paths in a 2d array

I have a two-dimensional array of integers and want to find the path with the lowest sum from the left column to the right column, when going up, down and left is possible. I started with a loop of all rows and tried to build up the paths as lists.
(defparameter *test-array*
#2A((131 673 234 103 18)
(201 96 342 965 150)
(630 803 746 422 111)
(537 699 497 121 956)
(805 732 524 37 331)))
(defun find-paths (array &aux (height (array-dimension array 0)) (width (array-dimension array 1)))
"Returns the possible paths across a given 2d array from the left column to
the right column."
(loop :for i :from 0 :below height
;; We have three ways per starting point up, left and down.
;; In the first and last row there are two ways, only.
:append (loop :for (j l) :in '((1 0) (0 1) (-1 0))
:when (and (>= (+ j i) 0) (< (+ j i) height))
:collect (list (aref array i 0) (aref array (+ i j) l))) :into paths
:finally (return paths)))
I was wondering if this really leads to a good solution. I am afraid that it will get more and more complex and memory comsuming to turn the whole array in a list of lists representing all possible paths. As far as I understand, it is a graph, basically. But how could I create the graph from the array without wasting memory?
This seems solvable by dynamic programming.
I'd create a new array with the same dimensions, which holds two values at each coordinate: the best path to it, and its cost. Initialize these values at the leftmost column, then propagate them all the way to the right.
Then, propagate each element path up as far as it is an improvement. Then left, then down. Cycle through the directions until none of them gives an improvement.
Finally, the best path at the rightmost column is the solution.

Finding N elements in array whoes xor equals P

I am working on a problem in which I am expected to find the number of combinations of N<20 elements in array whose XOR equals P.
For example:
our array is {2 4 5 2 7}
1) if N=2 and P=6,
The answer is 2 (as we can choose only (2 xor 4) = 6 and (4 xor 2) = 6)
{2 4 5 2 7} or {2 4 5 2 7}
2) if N=3 and P=6
The answer is 1 ((4 xor 5 xor 7) = 6)
The size of array can be really huge (something about 10^6) so I am looking for fast algorithm to solve that problem.
EDIT not working because N is fixed
Using linear algebra:
As suggested by #blazs, you can view P and each number of your array as vectors in a Z/2Z vector space. What's more, since XOR is associative and commutative, you're not looking for combinations of elements of your array, but sets of these elements, and a set can also be encoded as a Z/2Z vector.
So you'll end up with a matrix equation like M*S=P, where P is the xor-sum in Z/2Z vector format, M is the matrix which columns are the elements of the array in Z/2Z format , and S is the unknown of the equation.
Since you're only interested in the size of the solution space, all you need to do is find the dimension of the solution space, and then raise 2 to the power of it.
Proposed recursive algorithm, may be faster than brute force:
Find some bit of P which is 1. Any solution combination must contain at least one number which has a 1 in that bit.
For each element K of the array which has a 1 at that bit, recur with:
P' = P xor K (xor - substraction)
arr' = arr - {set of J in arr which have a 1 in that bit, and which index is less than or equal to K} (because we're assuming K is the first element of the combination with a 1 at this position in the solution space)
N = N - 1
Termination cases:
if P=0, and N=0, one solution
if N=0 and P!=0, no solution
if arr is empty, no solution
if there's a bit where P has a 1 and no element of arr does, no solution
Note that XOR is associative and commutative, so we're counting sets, not combinations.

How to rearrange an array in such a way that each element is greater/smaller than its neighbours

For example, if the numbers are:
30, 12, 49, 6, 10, 50, 13
The array will be:
[10, 6, 30, 12, 49, 13, 50]
As you can see:
6 is smaller than both 10 and 30 and
49 is greater than 12 and 13 and so on.
The numbers are all different and real. I need the most efficient algorithm.
This can be done in O(n):
Find median in O(n) (description is available in Wikipedia
Put every element larger than the median on odd places and every smaller element - on even places
Of course, this assumes that all elements are distinct, otherwise sometimes it will fail.
Assuming the numbers are all distinct, the easiest way is probably to sort the numbers then interleave the first and second halves of the sorted list. This will guarantee the high/low/high/low/high/low/.... pattern that you need.
This algorithm is O(n log n) which should be efficient enough for most purposes, and may benefit from optimised sorting routines in your standard library.
If the numbers are not distinct, then it is possible that there is no solution (e.g. if the numbers are all equal)
Someone posted this question as a dupe to this but the solution over there is better than the accepted solution here so I figured I'd post it here.
Basically the key is for every three numbers where it has to hold that a < b > c you look at the sequence and swap the biggest number into the center. Then you increment by 2 to get to the next sequence like a < b > c and do the same thing.
Technically the solution still runs in O(n) like the accepted solution, but it is a better O(n) and it is much simpler because the median of medians algo is tricky to implement. Hopefully anyone who favorited this problem will at least see this solution, I can post the code if anyone is interested.
I'm not too knowledgeable about complexity, but here's my idea.
For even length lists:
(For our odd length example,
put 30 aside to make the list even)
1. Split the list into chunks of 2 => [[12,49],[6,10],[50,13]]
2. Sort each chunk => [[12,49],[6,10],[13,50]]
3. Reverse-sort the chunks by
comparing the last element of
one to the first element of
the second => [[12,49],[13,50],[6,10]]
For odd length lists:
4. Place the removed first element in
the first appropriate position => [30,12,49,13,50,6,10]
Haskell code:
import Data.List (sortBy)
import Data.List.Split (chunksOf)
rearrange :: [Int] -> [Int]
rearrange xs
| even (length xs) = rearrangeEven xs
| null (drop 1 xs) = xs
| otherwise = place (head xs) (rearrangeEven (tail xs))
where place x (y1:y2:ys)
| (x < y1 && y1 > y2) || (x > y1 && y1 < y2) = (x:y1:y2:ys)
| otherwise = place' x (y1:y2:ys)
place' x (y1:y2:ys)
| (x < y1 && x < y2) || (x > y1 && x > y2) = (y1:x:y2:ys)
| otherwise = y1 : (place' x (y2:ys))
rearrangeEven = concat
. sortBy (\a b -> compare (head b) (last a))
. map sort
. chunksOf 2
Output:
*Main> rearrange [30,12,49,6,10,50,13]
[30,12,49,13,50,6,10]
*Main> rearrange [1,2,3,4]
[3,4,1,2]

How to vectorize this matrix multiplication in matlab

I have 2 matrices A (nxm) and B (nxd) and want to multiply element-wise each column of A with a row of B. There are m columns in A and n 1xd vectors in B so the results are m nxd matrices. Then I want to sum(result_i, 1) to get m 1xd vectors, which I want to apply vertcat to get a mxd matrix. I'm doing this operations using for loop and it is slow because n and d are big. How can I vectorize this in matlab to make it faster? Thank you.
EDIT:
You're all right: I was confused by my own question. What I meant by "multiply element-wise each column of A with a row of B" is to multiply n elements of a column in A with the corresponding n rows of B. What I want to do with one column of A is as followed (and I repeat this for m columns of A, then vertcat the C's vector together to get an mxd matrix):
column_of_A =
3
3
1
B =
3 1 3 3
2 2 1 2
1 3 3 3
C = sum(diag(column_of_A)*B, 1)
16 12 15 18
You can vectorize your operation the following way. Note, however, that vectorizing comes at the cost of higher memory usage, so the solution may end up not working for you.
%# multiply nxm A with nx1xd B to create a nxmxd array
tmp = bsxfun(#times,A,permute(B,[1 3 2]));
%# sum and turn into mxd
out = squeeze(sum(tmp,1));
You may want to do everything in one line, which may help the Matlab JIT compiler to save on memory.
EDIT
Here's a way to replace the first line if you don't have bsxfun
[n,m] = size(A);
[n,d] = size(B);
tmp = repmat(A,[1 1 d]) .* repmat(permute(B,[1 3 2]),[1,m,1]);
It's ugly, but as far as I can see, it works. I'm not sure it will be faster than your loop though, plus, it has a large memory overhead. Anyway, here goes:
A_3D = repmat(reshape(A, size(A, 1), 1, size(A, 2)), 1, size(B, 2));
B_3D = repmat(B, [ 1 1 size(A, 2)]);
result_3D = sum(A_3D .* B_3D, 1);
result = reshape(result_3D, size(A, 2), size(B, 2))
What it does is: make A into a 3D matrix of size n x 1 x m, so one column in each index of the 3rd dimension. Then we repeat the matrix so we get an n x d x m matrix. We repeat B in the 3rd dimension as well. We then do a piecewise multiplication of all the elements and sum them. The resulting matrix is a 1 x d x m matrix. We reshape this into a m x d matrix.
I'm pretty sure I switched around the size of the dimensions a few times in my explanation, but I hope you get the general gist.
Multiplying with a diagonal matrix seems at least twice as fast, but I couldn't find a way to use diag, since it wants a vector or 2D matrix as input. I might try again later tonight, I feel there must be a faster way :).
[Edit] Split up the command in parts to at least make it a little bit readable.
This is the way I would do this:
sum(repmat(A,1,4).*B)
If you don't know the number of columns of B:
sum(repmat(A,1,size(B,2)).*B)

Resources