Adding a number to each column of a matrix - matrix

I have a matrix
A = [[ 1. 2. 3.]
[ 4. 5. 6.]]
and a vector
b = [ 5. 10. 15.]
I want to add each column of A (A[:,i]) to b[i], i.e.
[[ 6. 12. 18.]
[ 9. 15. 21.]]
an easy way to do it would be
A = tf.constant([[1., 2, 3],[1, 2, 3]])
b = tf.constant([[5, 10, 15.]])
e = tf.ones((2,1))
a + tf.matmul( e, b ) # outer product "repmat"
But it seems terribly wasteful to do this and have to construct an entire auxiliary matrix which we will eventually throw out. Is there a more idomatic way of doing this without writing my own op?

As mentioned you can do A + b:
import tensorflow as tf
tf.InteractiveSession()
A = tf.constant([[1., 2, 3], [4, 5, 6]])
b = tf.constant([[5, 10, 15.]])
(A + b).eval()
returns:
array([[ 6., 12., 18.],
[ 9., 15., 21.]], dtype=float32)
The reason this works is because of array broadcasting. The Numpy broadcasting page has great info and tensorflow broadcasting works the same way. Basically for each dimension (moving from trailing dimension to leading dimension) tensorflow/numpy attempts checks to see if the dimensions are compatible (either they have the same number of elements or one of them only has 1 element).
In your case A is of shape [2, 3] and b is of shape [1, 3]. The second dimensions match, but because b has a first dimension with only a single element that element of b is "broadcast" along the first dimension of A (two elements).

Related

pytorch: efficient way to perform operations on 2 tensors of different sizes, where one has a one-to-many relation

I have 2 tensors. The first tensor is 1D (e.g. a tensor of 3 values). The second tensor is 2D, with the first dim as the IDs to first tensor in a one-many relationship (e.g. a tensor with a shape of 6, 2)
# e.g. simple example of dot product
import torch
a = torch.tensor([2, 4, 3])
b = torch.tensor([[0, 2], [0, 3], [0, 1], [1, 4], [2, 3], [2, 1]]) # 1st column is the index to tensor a, 2nd column is the value
output = [(2*2)+(2*3)+(2*1),(4*4),(3*3)+(3*1)]
output = [12, 16, 12]
Current what I have is to find the size of each id in b (e.g. [3,1,2]) then using torch.split to group them into a list of tensors and running a for loop through the groups. It is fine for a small tensor, but when the size of the tensors are in millions, with tens of thousands of arbitrary-sized groups, it became very slow.
Any better solutions?
You can use numpy.bincount or torch.bincount to sum the elements of b by key:
import numpy as np
a = np.array([2,4,3])
b = np.array([[0,2], [0,3], [0,1], [1,4], [2,3], [2,1]])
print( np.bincount(b[:,0], b[:,1]) )
# [6. 4. 4.]
print( a * np.bincount(b[:,0], b[:,1]) )
# [12. 16. 12.]
import torch
a = torch.tensor([2,4,3])
b = torch.tensor([[0,2], [0,3], [0,1], [1,4], [2,3], [2,1]])
torch.bincount(b[:,0], b[:,1])
# tensor([6., 4., 4.], dtype=torch.float64)
a * torch.bincount(b[:,0], b[:,1])
# tensor([12., 16., 12.], dtype=torch.float64)
References:
numpy.bincount official documentation;
torch.bincount official documentation;
How can I reduce a numpy array based on a key rather than an axis?
Another alternative in pytorch if gradient is needed.
import torch
a = torch.tensor([2,4,3])
b = torch.tensor([[0,2], [0,3], [0,1], [1,4], [2,3], [2,1]])
output = torch.zeros(a.shape[0], dtype=torch.long).index_add_(0, b[:, 0], b[:, 1]) * a
alternatively, torch.tensor.scatter_add also works.

Sparse to Dense Matrix reduces its dimension when there are repetitions

I have a set of indices that I want to convert them to encodings. In order to do so :
i = [2, 1, 3, 4]
s = sparse(i, 1:lenght(i), 1)
s = full(s);
This works fine as expected but when the array i = [2, 1, 3, 3]. The full function gives a 3 by 4 matrix instead of 4 by 4. Julia thinks that the last row is unnecessary and deletes it which ,for my case, is not.
Is it possible to create a square matrix by using sparse and full when there are repetitions inside the index array i?
B.R.
Just supply the dimensions you want as additional arguments, e.g.:
s = sparse(i, 1:length(i), 1, 4, 4)
The details are explained in help for sparse.

pairwise distinct left ends in all segments

I am provided with M segments of form [L,R] of N elements of an array.I need to change these segments in such a way that all segments have pairwise distinct left ends.
Example : Let suppose we have 5 elements in array and we have 4 segments : [1,2],[1,3],[2,4] and [4,5] then after making all the left ends pairwise disjoint we have [1,2],[3,3],[2,4] and [4,5].Here all segments have different left ends
Let's see if I got this. I suggest
You sort all segments according to the right end.
Then you fix all the left ends, starting with the smallest right end working towards larger right ends. Fixing means you replace the current left end with the next available value.
In Python it looks like this:
def fit_intervals(datalist):
d1 = sorted(datalist, key=lambda x : x[1])
taken = set()
def find_next_free(x):
while x in taken:
x = x + 1
taken.add(x)
return x
for interval in d1:
interval[0] = find_next_free( interval[0] )
data = [ [4,5], [1,9], [1,2], [1,3], [2,4] ]
fit_intervals(data)
print(data)
output: [[4, 5], [5, 9], [1, 2], [2, 3], [3, 4]]
This function find_next_free currently uses a simple linear algorithm, if necessary this could certainly be improved.

Combine lists to the least possible amount of 2-dimensional lists

Sorry for the bad description in the title.
Consider a 2-dimensional list such as this:
list = [
[1, 2],
[2, 3],
[3, 4]
]
If I were to extract all possible "vertical" combinations of this list, for a total of 2*2*2=8 combinations, they would be the following sequences:
1, 2, 3
2, 2, 3
1, 3, 3
2, 3, 3
1, 2, 4
2, 2, 4
1, 3, 4
2, 3, 4
Now, let's say I remove some of these sequences. Let's say I only want to keep sequences which have either the number 2 in position #1 OR number 4 in position #3. Then I would be left with these sequences:
2, 2, 3
2, 3, 3
1, 2, 4
2, 2, 4
1, 3, 4
2, 3, 4
The problem
I would like to re-combine these remaining sequences to the least possible amount of 2-dimensional lists needed to contain all sequences but no less or no more.
By doing so, the resulting 2-dimensional lists in this particular example would be:
list_1 = [
[2],
[2, 3],
[3, 4]
]
list_2 = [
[1],
[2, 3],
[4]
]
In this particular case, the resulting lists can be thought out. But how would I go about if there were thousands of sequences yielding hundereds of 2-dimensional lists? I have been trying to come up with a good algorithm for two weeks now, but I am getting nowhere near a satisfying result.
Divide et impera, or divide and conquer. If we have a logical expression, stating that the value at position x should be a or the value at position y should be b, then we have 3 cases:
a is the value at position x and b is the value at position y
a is the value at position x and b is not the value at position y
a is not the value at position x and b is the value at position y
So, first you generate all your scenarios, you know now that you have 3 scenarios.
Then, you effectively separate your cases and handle all of them in a sub-routine as they were your main tasks. The philosophy behind divide et imera is to reduce your complex problem into several similar, but less complex problems, until you reach triviality.

Find the middle element in merged arrays in O(logn)

We have two sorted arrays of the same size n. Let's call the array a and b.
How to find the middle element in an sorted array merged by a and b?
Example:
n = 4
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
merged = [1, 2, 3, 3, 4, 4, 5, 6]
mid_element = merged[(0 + merged.length - 1) / 2] = merged[3] = 3
More complicated cases:
Case 1:
a = [1, 2, 3, 4]
b = [3, 4, 5, 6]
Case 2:
a = [1, 2, 3, 4, 8]
b = [3, 4, 5, 6, 7]
Case 3:
a = [1, 2, 3, 4, 8]
b = [0, 4, 5, 6, 7]
Case 4:
a = [1, 3, 5, 7]
b = [2, 4, 6, 8]
Time required: O(log n). Any ideas?
Look at the middle of both the arrays. Let's say one value is smaller and the other is bigger.
Discard the lower half of the array with the smaller value. Discard the upper half of the array with the higher value. Now we are left with half of what we started with.
Rinse and repeat until only one element is left in each array. Return the smaller of those two.
If the two middle values are the same, then pick arbitrarily.
Credits: Bill Li's blog
Quite interesting task. I'm not sure about O(logn), but solution O((logn)^2) is obvious for me.
If you know position of some element in first array then you can find how many elements are smaller in both arrays then this value (you know already how many smaller elements are in first array and you can find count of smaller elements in second array using binary search - so just sum up this two numbers). So if you know that number of smaller elements in both arrays is less than N, you should look in to the upper half in first array, otherwise you should move to the lower half. So you will get general binary search with internal binary search. Overall complexity will be O((logn)^2)
Note: if you will not find median in first array then start initial search in the second array. This will not have impact on complexity
So, having
n = 4 and a = [1, 2, 3, 4] and b = [3, 4, 5, 6]
You know the k-th position in result array in advance based on n, which is equal to n.
The result n-th element could be in first array or second.
Let's first assume that element is in first array then
do binary search taking middle element from [l,r], at the beginning l = 0, r = 3;
So taking middle element you know how many elements in the same array smaller, which is middle - 1.
Knowing that middle-1 element is less and knowing you need n-th element you may have [n - (middle-1)]th element from second array to be smaller, greater. If that's greater and previos element is smaller that it's what you need, if it's greater and previous is also greater we need to L = middle, if it's smaller r = middle.
Than do the same for the second array in case you did not find solution for first.
In total log(n) + log(n)

Resources