4

I have a 1d vector and want to generate a matrix based on the pairwise comparison of the vector in TensorFlow. I need to compare each element in the vector to all the others (including itself), and if they are identical, the corresponding matrix value will be 1, and -1 otherwise. For example, there is a vector of [1,2,3,4,1], then the desired matrix is

[[1,-1,-1,-1,1],
 [-1,1,-1,-1,-1],
 [-1,-1,1,-1,-1],
 [-1,-1,-1,1,-1],
 [1,-1,-1,-1,1]].

The question is how to generate such a matrix in TensorFlow.

Maxim
  • 52,561
  • 27
  • 155
  • 209
ALeex
  • 187
  • 1
  • 11
  • Actually I do want to compare the elements of in a 1d vector. Say the vector has a length of 5, then there will be 25 comparisons and therefore generates a 5x5 matrix based on the result of each comparison. – ALeex Mar 16 '18 at 21:14

3 Answers3

2

Idea

To compute pairwise op you can do the following trick: expand the vector to two 2-dimensional vectors: [n, 1] and [1, n], and apply the op to them. Due to broadcasting it will produce the [n, n] matrix filled with op results for all pairs inside the vector.

In your case, an op is a comparison, but it can be any binary operation.

Tensorflow

For illustration, here are two one-liners. The first one produces the boolean pairwise matrix, the second one - the matrix of -1 and 1 (what you asked).

import tensorflow as tf

tf.InteractiveSession()
v = tf.constant([1, 2, 3, 4, 1])

x = tf.equal(v[:, tf.newaxis], v[tf.newaxis, :])
print(x.eval())

x = 1 - 2 * tf.cast(x, tf.float32)
print(x.eval())

Result:

[[ True False False False  True]
 [False  True False False False]
 [False False  True False False]
 [False False False  True False]
 [ True False False False  True]]
[[ 1 -1 -1 -1  1]
 [-1  1 -1 -1 -1]
 [-1 -1  1 -1 -1]
 [-1 -1 -1  1 -1]
 [ 1 -1 -1 -1  1]]

Numpy

The same in numpy is even simpler using np.where:

import numpy as np

v = np.array([1, 2, 3, 4, 1])

x = v[:, np.newaxis] == v[np.newaxis, :]
print(x)

x = np.where(x, 1, -1)
print(x)

Output is the same:

[[ True False False False  True]
 [False  True False False False]
 [False False  True False False]
 [False False False  True False]
 [ True False False False  True]]
[[ 1 -1 -1 -1  1]
 [-1  1 -1 -1 -1]
 [-1 -1  1 -1 -1]
 [-1 -1 -1  1 -1]
 [ 1 -1 -1 -1  1]]
Maxim
  • 52,561
  • 27
  • 155
  • 209
1

I don't know if TensorFlow has anything like this builtin, but there's a pretty straightforward approach in NumPy. It works by taking all products of the elements, and picking out locations where the product of two elements x and y is equal to x ** 2.0.

Given a vector

v = np.array((1, 2, 3, 4, 1)).reshape(-1, 1) # shape == (5, 1)

you can construct the "similarity" matrix you want by doing:

sim = np.where(v.dot(v.T) == np.square(v), 1, -1)

sim will look like so:

array([[ 1, -1, -1, -1,  1],
       [-1,  1, -1, -1, -1],
       [-1, -1,  1, -1, -1],
       [-1, -1, -1,  1, -1],
       [ 1, -1, -1, -1,  1]])
bnaecker
  • 6,152
  • 1
  • 20
  • 33
  • Thank you for your answer, I thought about generating a np matrix and then convert it into tensorflow tensor. But apparently, I don't know how to link np to tf graph. By any chance do you know how it works? – ALeex Mar 16 '18 at 21:31
  • I've no idea, but it looks like you might be able to use this approach directly in TensorFlow, without converting whatever stores your data there to an ndarray and back. Look at [`tf.where()`](https://www.tensorflow.org/api_docs/python/tf/where), which might point you in the right direction. Maybe construct a `tf.constant` from the vector you have, then do the operation I've described, substituting `tf.where()`, `tf.square()`, and `tf.matmul()`. – bnaecker Mar 16 '18 at 21:37
  • Are you sure tf.where() does the same thing as np.where? – ALeex Mar 16 '18 at 21:57
  • It seems to do the same operation, but it may not allow scalars in for the second and third arguments. They may need to be tensors of the same rank as the first argument. I've never used it. – bnaecker Mar 16 '18 at 22:00
0

Here is a simple way to do it:

In [123]: x = tf.placeholder(tf.float32, shape=(1, 5))

In [124]: z = tf.equal(tf.matmul(tf.transpose(x), x), tf.square(x))

In [125]: y = 2 * tf.cast(z, tf.int32) - 1

In [126]: sess = tf.Session()

In [127]: sess.run(y, feed_dict={x: np.array([1, 2, 3, 4, 1])[None, :]})
Out[127]: 
array([[ 1, -1, -1, -1,  1],
       [-1,  1, -1, -1, -1],
       [-1, -1,  1, -1, -1],
       [-1, -1, -1,  1, -1],
       [ 1, -1, -1, -1,  1]], dtype=int32)
ely
  • 74,674
  • 34
  • 147
  • 228