Reshaping tensors in a 3D numpy matrix - arrays
I'm essentially trying to accomplish this and then this but with a 3D matrix, say (128,128,60,6). The 4th dimension is an array vector that represents the diffusion array at that voxel, e.g.:
d[30,30,30,:] = [dxx, dxy, dxz, dyy, dyz, dzz] = D_array
Where dxx etc. are diffusion for a particular direction. D_array can also be seen as a triangular matrix (since dxy == dyx etc.). So I can use those 2 other answers to get from D_array to D_square, e.g.
D_square = [[dxx, dxy, dxz], [dyx, dyy, dyz],[dzx, dzy, dzz]]
I can't seem to figure out the next step however - how to apply that unit transformation of a D_array into D_square to the whole 3D volume.
Here's the code snippet that works on a single tensor:
#this solves an linear eq. that provides us with diffusion arrays at each voxel in a 3D space
D = np.einsum('ijkt,tl->ijkl',X,bi_plus)
#our issue at this point is we have a vector that represents a triangular matrix.
# first make a tri matx from the vector, testing on unit tensor first
D_tri = np.zeros((3,3))
D_array = D[30][30][30]
D_tri[np.triu_indices(3)] = D_array
# then getting the full sqr matrix
D_square = D_tri.T + D_tri
np.fill_diagonal(D_square, np.diag(D_tri))
So what would be the numpy-way of formulating that unit transformation of the Diffusion tensor to the whole 3D volume all at once?
Approach #1
Here's one using row, col indices from triu_indices for indexing along last two axes into an initialized output array -
def squareformnd_rowcol_integer(ar, n=3):
out_shp = ar.shape[:-1] + (n,n)
out = np.empty(out_shp, dtype=ar.dtype)
row,col = np.triu_indices(n)
# Get a "rolled-axis" view with which the last two axes come to the front
# so that we could index into them just like for a 2D case
out_rolledaxes_view = out.transpose(np.roll(range(out.ndim),2,0))
# Assign permuted version of input array into rolled output version
arT = np.moveaxis(ar,-1,0)
out_rolledaxes_view[row,col] = arT
out_rolledaxes_view[col,row] = arT
return out
Approach #2
Another one with the last two axes merged into one and then indexing with linear indices -
def squareformnd_linear_integer(ar, n=3):
out_shp = ar.shape[:-1] + (n,n)
out = np.empty(out_shp, dtype=ar.dtype)
row,col = np.triu_indices(n)
idx0 = row*n+col
idx1 = col*n+row
ar2D = ar.reshape(-1,ar.shape[-1])
out.reshape(-1,n**2)[:,idx0] = ar2D
out.reshape(-1,n**2)[:,idx1] = ar2D
return out
Approach #3
Finally altogether a new method using masking and should be better with performance as most masking based ones are when it comes to indexing -
def squareformnd_masking(ar, n=3):
out = np.empty((n,n)+ar.shape[:-1] , dtype=ar.dtype)
r = np.arange(n)
m = r[:,None]<=r
arT = np.moveaxis(ar,-1,0)
out[m] = arT
out.swapaxes(0,1)[m] = arT
new_axes = range(out.ndim)[2:] + [0,1]
return out.transpose(new_axes)
Timings on (128,128,60,6) shaped random array -
In [635]: ar = np.random.rand(128,128,60,6)
In [636]: %timeit squareformnd_linear_integer(ar, n=3)
...: %timeit squareformnd_rowcol_integer(ar, n=3)
...: %timeit squareformnd_masking(ar, n=3)
10 loops, best of 3: 103 ms per loop
10 loops, best of 3: 103 ms per loop
10 loops, best of 3: 53.6 ms per loop
A vectorized way to do it:
# Gets the triangle matrix
d_tensor = np.zeros(128, 128, 60, 3, 3)
triu_idx = np.triu_indices(3)
d_tensor[:, :, :, triu_idx[0], triu_idx[1]] = d
# Make it symmetric
diagonal = np.zeros(128, 128, 60, 3, 3)
idx = np.arange(3)
diagonal[:, :, :, idx, idx] = d_tensor[:, :, :, idx, idx]
d_tensor = np.transpose(d_tensor, (0, 1, 2, 4, 3)) + d_tensor - diagonal
Related
Find Minimum Score Possible
Problem statement: We are given three arrays A1,A2,A3 of lengths n1,n2,n3. Each array contains some (or no) natural numbers (i.e > 0). These numbers denote the program execution times. The task is to choose the first element from any array and then you can execute that program and remove it from that array. For example: if A1=[3,2] (n1=2), A2=[7] (n2=1), A3=[1] (n3=1) then we can execute programs in various orders like [1,7,3,2] or [7,1,3,2] or [3,7,1,2] or [3,1,7,2] or [3,2,1,7] etc. Now if we take S=[1,3,2,7] as the order of execution the waiting time of various programs would be for S[0] waiting time = 0, since executed immediately, for S[1] waiting time = 0+1 = 1, taking previous time into account, similarly, for S[2] waiting time = 0+1+3 = 4 for S[3] waiting time = 0+1+3+2 = 6 Now the score of array is defined as sum of all wait times = 0 + 1 + 4 + 6 = 11, This is the minimum score we can get from any order of execution. Our task is to find this minimum score. How can we solve this problem? I tried with approach trying to pick minimum of three elements each time, but it is not correct because it gets stuck when two or three same elements are encountered. One more example: if A1=[23,10,18,43], A2=[7], A3=[13,42] minimum score would be 307.
The simplest way to solve this is with dynamic programming (which runs in cubic time). For each array A: Suppose you take the first element from array A, i.e. A[0], as the next process. Your total cost is the wait-time contribution of A[0] (i.e., A[0] * (total_remaining_elements - 1)), plus the minimal wait time sum from A[1:] and the rest of the arrays. Take the minimum cost over each possible first array A, and you'll get the minimum score. Here's a Python implementation of that idea. It works with any number of arrays, not just three. def dp_solve(arrays: List[List[int]]) -> int: """Given list of arrays representing dependent processing times, return the smallest sum of wait_time_before_start for all job orders""" arrays = [x for x in arrays if len(x) > 0] # Remove empty #functools.lru_cache(100000) def dp(remaining_elements: Tuple[int], total_remaining: int) -> int: """Returns minimum wait time sum when suffixes of each array have lengths in 'remaining_elements' """ if total_remaining == 0: return 0 rem_elements_copy = list(remaining_elements) best = 10 ** 20 for i, x in enumerate(remaining_elements): if x == 0: continue cost_here = arrays[i][-x] * (total_remaining - 1) if cost_here >= best: continue rem_elements_copy[i] -= 1 best = min(best, dp(tuple(rem_elements_copy), total_remaining - 1) + cost_here) rem_elements_copy[i] += 1 return best return dp(tuple(map(len, arrays)), sum(map(len, arrays))) Better solutions The naive greedy strategy of 'smallest first element' doesn't work, because it can be worth it to do a longer job to get a much shorter job in the same list done, as the example of A1 = [100, 1, 2, 3], A2 = [38], A3 = [34], best solution = [100, 1, 2, 3, 34, 38] by user3386109 in the comments demonstrates. A more refined greedy strategy does work. Instead of the smallest first element, consider each possible prefix of the array. We want to pick the array with the smallest prefix, where prefixes are compared by average process time, and perform all the processes in that prefix in order. A1 = [ 100, 1, 2, 3] Prefix averages = [(100)/1, (100+1)/2, (100+1+2)/3, (100+1+2+3)/4] = [ 100.0, 50.5, 34.333, 26.5] A2=[38] A3=[34] Smallest prefix average in any array is 26.5, so pick the prefix [100, 1, 2, 3] to complete first. Then [34] is the next prefix, and [38] is the final prefix. And here's a rough Python implementation of the greedy algorithm. This code computes subarray averages in a completely naive/brute-force way, so the algorithm is still quadratic (but an improvement over the dynamic programming method). Also, it computes 'maximum suffixes' instead of 'minimum prefixes' for ease of coding, but the two strategies are equivalent. def greedy_solve(arrays: List[List[int]]) -> int: """Given list of arrays representing dependent processing times, return the smallest sum of wait_time_before_start for all job orders""" def max_suffix_avg(arr: List[int]): """Given arr, return value and length of max-average suffix""" if len(arr) == 0: return (-math.inf, 0) best_len = 1 best = -math.inf curr_sum = 0.0 for i, x in enumerate(reversed(arr), 1): curr_sum += x new_avg = curr_sum / i if new_avg >= best: best = new_avg best_len = i return (best, best_len) arrays = [x for x in arrays if len(x) > 0] # Remove empty total_time_sum = sum(sum(x) for x in arrays) my_averages = [max_suffix_avg(arr) for arr in arrays] total_cost = 0 while True: largest_avg_idx = max(range(len(arrays)), key=lambda y: my_averages[y][0]) _, n_to_remove = my_averages[largest_avg_idx] if n_to_remove == 0: break for _ in range(n_to_remove): total_time_sum -= arrays[largest_avg_idx].pop() total_cost += total_time_sum # Recompute the changed array's avg my_averages[largest_avg_idx] = max_suffix_avg(arrays[largest_avg_idx]) return total_cost
In MATLAB how can I write out a multidimensional array as a string that looks like a raw numpy array?
The Goal (Forgive me for length of this, it's mostly background and detail.) I'm contributing to a TOML encoder/decoder for MATLAB and I'm working with numerical arrays right now. I want to input (and then be able to write out) the numerical array in the same format. This format is the nested square-bracket format that is used by numpy.array. For example, to make multi-dimensional arrays in numpy: The following is in python, just to be clear. It is a useful example though my work is in MATLAB. 2D arrays >> x = np.array([1,2]) >> x array([1, 2]) >> x = np.array([[1],[2]]) >> x array([[1], [2]]) 3D array >> x = np.array([[[1,2],[3,4]],[[5,6],[7,8]]]) >> x array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) 4D array >> x = np.array([[[[1,2],[3,4]],[[5,6],[7,8]]],[[[9,10],[11,12]],[[13,14],[15,16]]]]) >> x array([[[[ 1, 2], [ 3, 4]], [[ 5, 6], [ 7, 8]]], [[[ 9, 10], [11, 12]], [[13, 14], [15, 16]]]]) The input is a logical construction of the dimensions by nested brackets. Turns out this works pretty well with the TOML array structure. I can already successfully parse and decode any size/any dimension numeric array with this format from TOML to MATLAB numerical array data type. Now, I want to encode that MATLAB numerical array back into this char/string structure to write back out to TOML (or whatever string). So I have the following 4D array in MATLAB (same 4D array as with numpy): >> x = permute(reshape([1:16],2,2,2,2),[2,1,3,4]) x(:,:,1,1) = 1 2 3 4 x(:,:,2,1) = 5 6 7 8 x(:,:,1,2) = 9 10 11 12 x(:,:,2,2) = 13 14 15 16 And I want to turn that into a string that has the same format as the 4D numpy input (with some function named bracketarray or something): >> str = bracketarray(x) str = '[[[[1,2],[3,4]],[[5,6],[7,8]]],[[[9,10],[11,12]],[[13,14],[15,16]]]]' I can then write out the string to a file. EDIT: I should add, that the function numpy.array2string() basically does exactly what I want, though it adds some other whitespace characters. But I can't use that as part of the solution, though it is basically the functionality I'm looking for. The Problem Here's my problem. I have successfully solved this problem for up to 3 dimensions using the following function, but I cannot for the life of me figure out how to extend it to N-dimensions. I feel like it's an issue of the right kind of counting for each dimension, making sure to not skip any and to nest the brackets correctly. Current bracketarray.m that works up to 3D function out = bracketarray(in, internal) in_size = size(in); in_dims = ndims(in); % if array has only 2 dimensions, create the string if in_dims == 2 storage = cell(in_size(1), 1); for jj = 1:in_size(1) storage{jj} = strcat('[', strjoin(split(num2str(in(jj, :)))', ','), ']'); end if exist('internal', 'var') || in_size(1) > 1 || (in_size(1) == 1 && in_dims >= 3) out = {strcat('[', strjoin(storage, ','), ']')}; else out = storage; end return % if array has more than 2 dimensions, recursively send planes of 2 dimensions for encoding else out = cell(in_size(end), 1); for ii = 1:in_size(end) %<--- this doesn't track dimensions or counts of them out(ii) = bracketarray(in(:,:,ii), 'internal'); %<--- this is limited to 3 dimensions atm. and out(indexing) need help end end % bracket the final bit together if in_size(1) > 1 || (in_size(1) == 1 && in_dims >= 3) out = {strcat('[', strjoin(out, ','), ']')}; end end Help me Obi-wan Kenobis, y'all are my only hope! EDIT 2: Added test suite below and modified current code a bit. Test Suite Here is a test suite to use to see if the output is what it should be. Basically just copy and paste it into the MATLAB command window. For my current posted code, they all return true except the ones more than 3D. My current code outputs as a cell. If your solution output differently (like a string), then you'll have to remove the curly brackets from the test suite. isequal(bracketarray(ones(1,1)), {'[1]'}) isequal(bracketarray(ones(2,1)), {'[[1],[1]]'}) isequal(bracketarray(ones(1,2)), {'[1,1]'}) isequal(bracketarray(ones(2,2)), {'[[1,1],[1,1]]'}) isequal(bracketarray(ones(3,2)), {'[[1,1],[1,1],[1,1]]'}) isequal(bracketarray(ones(2,3)), {'[[1,1,1],[1,1,1]]'}) isequal(bracketarray(ones(1,1,2)), {'[[[1]],[[1]]]'}) isequal(bracketarray(ones(2,1,2)), {'[[[1],[1]],[[1],[1]]]'}) isequal(bracketarray(ones(1,2,2)), {'[[[1,1]],[[1,1]]]'}) isequal(bracketarray(ones(2,2,2)), {'[[[1,1],[1,1]],[[1,1],[1,1]]]'}) isequal(bracketarray(ones(1,1,1,2)), {'[[[[1]]],[[[1]]]]'}) isequal(bracketarray(ones(2,1,1,2)), {'[[[[1],[1]]],[[[1],[1]]]]'}) isequal(bracketarray(ones(1,2,1,2)), {'[[[[1,1]]],[[[1,1]]]]'}) isequal(bracketarray(ones(1,1,2,2)), {'[[[[1]],[[1]]],[[[1]],[[1]]]]'}) isequal(bracketarray(ones(2,1,2,2)), {'[[[[1],[1]],[[1],[1]]],[[[1],[1]],[[1],[1]]]]'}) isequal(bracketarray(ones(1,2,2,2)), {'[[[[1,1]],[[1,1]]],[[[1,1]],[[1,1]]]]'}) isequal(bracketarray(ones(2,2,2,2)), {'[[[[1,1],[1,1]],[[1,1],[1,1]]],[[[1,1],[1,1]],[[1,1],[1,1]]]]'}) isequal(bracketarray(permute(reshape([1:16],2,2,2,2),[2,1,3,4])), {'[[[[1,2],[3,4]],[[5,6],[7,8]]],[[[9,10],[11,12]],[[13,14],[15,16]]]]'}) isequal(bracketarray(ones(1,1,1,1,2)), {'[[[[[1]]]],[[[[1]]]]]'})
I think it would be easier to just loop and use join. Your test cases pass. function out = bracketarray_matlabbit(in) out = permute(in, [2 1 3:ndims(in)]); out = string(out); dimsToCat = ndims(out); if iscolumn(out) dimsToCat = dimsToCat-1; end for i = 1:dimsToCat out = "[" + join(out, ",", i) + "]"; end end This also seems to be faster than the route you were pursing: >> x = permute(reshape([1:16],2,2,2,2),[2,1,3,4]); >> tic; for i = 1:1e4; bracketarray_matlabbit(x); end; toc Elapsed time is 0.187955 seconds. >> tic; for i = 1:1e4; bracketarray_cris_luengo(x); end; toc Elapsed time is 5.859952 seconds.
The recursive function is almost complete. What is missing is a way to index the last dimension. There are several ways to do this, the neatest, I find, is as follows: n = ndims(x); index = cell(n-1, 1); index(:) = {':'}; y = x(index{:}, ii); It's a little tricky at first, but this is what happens: index is a set of n-1 strings ':'. index{:} is a comma-separated list of these strings. When we index x(index{:},ii) we actually do x(:,:,:,ii) (if n is 4). The completed recursive function is: function out = bracketarray(in) n = ndims(in); if n == 2 % Fill in your n==2 code here else % if array has more than 2 dimensions, recursively send planes of 2 dimensions for encoding index = cell(n-1, 1); index(:) = {':'}; storage = cell(size(in, n), 1); for ii = 1:size(in, n) storage(ii) = bracketarray(in(index{:}, ii)); % last dimension automatically removed end end out = { strcat('[', strjoin(storage, ','), ']') }; Note that I have preallocated the storage cell array, to prevent it from being resized in every loop iteration. You should do the same in your 2D case code. Preallocating is important in MATLAB for performance reasons, and the MATLAB Editor should warm you about this too.
Implementing Permutation of Complex Numbers In TensorFlow
In this associative lstm paper, http://arxiv.org/abs/1602.03032, they ask to permute a complex tensor. They have provided their code here: https://github.com/mohammadpz/Associative_LSTM/blob/master/bricks.py#L79 I'm trying to replicate this in tensorflow. Here is what I have done: # shape: C x F/2 # output = self.permutations: [num_copies x cell_size] permutations = [] indices = numpy.arange(self._dim / 2) #[1 ,2 ,3 ...64] for i in range(self._num_copies): numpy.random.shuffle(indices) #[4, 48, 32, ...64] permutations.append(numpy.concatenate( [indices, [ind + self._dim / 2 for ind in indices]])) #you're appending a row with two columns -- a permutation in the first column, and the same permutation + dim/2 for imaginary # C x F (numpy) self.permutations = tf.constant(numpy.vstack(permutations), dtype = tf.int32) #This is a permutation tensor that has the stored permutations # output = self.permutations: [num_copies x cell_size] def permute(complex_tensor): #complex tensor is [batch_size x cell_size] gather_tensor = tf.gather_nd(complex_tensor, self.permutations) return gather_tensor Basically, my question is: How efficiently can this be done in TensorFlow? Is there anyway to keep the batch size dimension fixed of complex tensor? Also, is gather_nd the best way to go about this? Or is it better to do a for loop and iterate over each row in self.permutations using tf.gather? def permute(self, complex_tensor): inputs_permuted = [] for i in range(self.permutations.get_shape()[0].value): inputs_permuted.append( tf.gather(complex_tensor, self.permutations[i])) return tf.concat(0, inputs_permuted) I thought that gather_nd would be far more efficient.
Nevermind, I figured it out, the trick is to just use permute the original input tensor using tf transpose. This will allow you then to do a tf.gather on the entire matrix. Then you can tf concat the matrices together. Sorry if this wasted anyone's time.
How to split a vector by the end indices of every group without using loops?
Let's say I have a vector "toSplit" of a certain size I also a vector of indexes that I want to split the vector. For example: splitInd = [ind1, ind2, ind3] My goal is to have three vectors: v1 = toSplit(1:ind1) v2 = toSplit(ind1+1:ind2) v3 = toSplit(ind2+1:ind3) v4 = toSplit(ind3+1:end) (The vectors, of course, are going to be part of a cell array). Running a loop is easy here. The question is how can I do it without running a loop (that, as we know, is not something that Matlab likes)?
With some preparation it's a job for accumarray: %// example data data = 1:10; splitInd = [3, 6, 9]; %// get index array subs = zeros(size(data)); subs(splitInd+1) = 1; subs = cumsum(subs) + 1; %// distributing values into cell array output = accumarray(subs(:),data(:),[],#(x) {x}); mat2cell is another option, shorter of code, but probably not faster. output = mat2cell(data, 1, diff([0 splitInd numel(data)]) )
It's also not unreasonable to just loop over your much shorter splitInd vector: splitInd = [1, splitInd, numel(toSplit)] for split = 1:numel(splitInd)-1 splits{split} = toSplit(splitInd(split):splitInd(split+1)); end Loops in MATLAB really aren't that inefficient these days and in this case you don't even need to loop over your entire toSplit vector.
matlab maximum of array with unknown dimension
I would like to compute the maximum and, more importantly, its coordinates of an N-by-N...by-N array, without specifying its dimensions. For example, let's take: A = [2 3]; B = [2 3; 3 4]; The function (lets call it MAXI) should return the following values for matrix A: [fmax, coor] = MAXI(A) fmax = 3 coor = 2 and for matrix B: [fmax, coor] = MAXI(B) fmax = 4 coor= 2 2 The main problem is not to develop a code that works for one class in particular, but to develop a code that as quickly as possible works for any input (with higher dimensions).
To find the absolute maximum, you'll have to convert your input matrix into a column vector first and find the linear index of the greatest element, and then convert it to the coordinates with ind2sub. This can be a little bit tricky though, because ind2sub requires specifying a known number of output variables. For that purpose we can employ cell arrays and comma-separated lists, like so: [fmax, coor] = max(A(:)); if ismatrix(A) C = cell(1:ndims(A)); [C{:}] = ind2sub(size(A), coor); coor = cell2mat(C); end EDIT: I've added an additional if statement that checks if the input is a matrix or a vector, and in case of the latter it returns the linear index itself as is. In a function, it looks like so: function [fmax, coor] = maxi(x) [fmax, coor] = max(A(:)); if ismatrix(A) C = cell(1:ndims(A)); [C{:}] = ind2sub(size(A), coor); coor = cell2mat(C); end Example A = [2 3; 3 4]; [fmax, coor] = maxi(A) fmax = 4 coor = 2 2