How to create a 2D tensor of Ones and Zeros like so:

Viewed 790

I need to create a tensor of ones and zeros based on an input tensor like this

input = tf.constant([3, 2, 4, 1, 0])

output =

0 0 0 0 0

0 0 0 1 0

0 0 1 1 0

0 0 1 1 1

0 1 1 1 1

Essentially, the index (i) of the each value of the input tensor + 1 specifies the row which I begin placing 1s in that column.

2 Answers

Here is an implementation with TensorFlow operations. See comments for details.

import tensorflow as tf

input = tf.placeholder(tf.int32, [None])
# Find indices that sort the input
# There is no argsort yet in the stable API,
# but you can do the same with top_k
_, order = tf.nn.top_k(-input, tf.shape(input)[0])
# Or use the implementation in contrib
order = tf.contrib.framework.argsort(input)
# Build triangular lower matrix
idx = tf.range(tf.shape(input)[0])
triangular = idx[:, tf.newaxis] > idx
# Reorder the columns according to the order
result = tf.gather(triangular, order, axis=1)
# Cast result from bool to int or float as needed
result = tf.cast(result, tf.int32)
with tf.Session() as sess:
    print(sess.run(result, feed_dict={input: [3, 2, 4, 1, 0]}))

Output:

[[0 0 0 0 0]
 [0 0 0 1 0]
 [0 0 1 1 0]
 [0 0 1 1 1]
 [0 1 1 1 1]]

This code gives the desired effect. But it doesn't use vectorized functions that could make this easier. There are some comments in the code.

Shapes are assumed based on the question. More testing is required if the input is changed.

init = tf.constant_initializer(np.zeros((5, 5)))

inputinit = tf.constant([3, 2, 4, 1, 0])

value = tf.gather( inputinit , [0,1,2,3,4])

sess = tf.Session()

#Combine rows to get the final desired tensor
def merge(a) :

    for i in range(0, ( value.get_shape()[0] - 1  )) :
        compare = tf.to_int32(
                    tf.not_equal(tf.gather(a, i ),
                                 tf.gather(a, ( i + 1 ))))
        a = tf.scatter_update(a, ( i + 1 ), compare)

    #Insert zeros in first row and move all other rows down by one position.
    #This eliminates the last row which isn't needed
    return tf.concat([tf.reshape([0,0,0,0,0],(1,5)),
                      a[0:1],a[1:2],a[2:3],a[3:4]],axis=0)


# Insert ones by stitching individual tensors together by inserting one in
# the desired position.
def insertones() :

    a = tf.get_variable("a", [5, 5], dtype=tf.int32, initializer=init)
    sess.run(tf.global_variables_initializer())

    for i in range(0, ( value.get_shape()[0]  )) :

        oldrow = tf.gather(a, i )

        index = tf.squeeze( value[i:( i + 1 )] )

        begin = oldrow[: index ]
        end = oldrow[index : 4]
        newrow = tf.concat([begin, tf.constant([1]), end], axis=0)

        if( i <= 4 ) :
            a = tf.scatter_update(a, i, newrow)
    return merge(a)

a = insertones()
print(sess.run(a))

Output is this.

[[0 0 0 0 0]

[0 0 0 1 0]

[0 0 1 1 0]

[0 0 1 1 1]

[0 1 1 1 1]]

Related