docstr: What happens when shape information isn't available statically?
  
  The short answer is: it still works. The long answer is: it still works, but
  arguments that shouldn't work due to argument shape mismatch can sometimes
  work without raising any errors! This can cause insidious bugs. This test
  verifies correct behaviour and also demonstrates kinds of shape mismatch
  that can go undetected. Look for `!!!DANGER!!!` below.
  
  Why this is possible: internally, `batched_index` flattens its inputs,
  then transforms the action indices you provide into indices into its
  flattened Q values tensor. So long as these flattened indices don't go
  out-of-bounds, and so long as your arguments are compatible with a few
  other bookkeeping operations, the operation will succeed.
  
  The moral: always provide as much shape information as you can! See also
  `testInputShapeChecks` for more on what shape checking can accomplish when
  only partial shape information is available.
docstr_tok: ["What","happens","when","shape","information","is","n't","available","statically","?","The","short","answer","is",":","it","still","works",".","The","long","answer","is",":","it","still","works",",","but","arguments","that","should","n't","work","due","to","argument","shape","mismatch","can","sometimes","work","without","raising","any","errors","!","This","can","cause","insidious","bugs",".","This","test","verifies","correct","behaviour","and","also","demonstrates","kinds","of","shape","mismatch","that","can","go","undetected",".","Look","for","`","!","!","!","DANGER","!","!","!","`","below",".","Why","this","is","possible",":","internally",",","`","batched_index","`","flattens","its","inputs",",","then","transforms","the","action","indices","you","provide","into","indices","into","its","flattened","Q","values","tensor",".","So","long","as","these","flattened","indices","do","n't","go","out-of-bounds",",","and","so","long","as","your","arguments","are","compatible","with","a","few","other","bookkeeping","operations",",","the","operation","will","succeed",".","The","moral",":","always","provide","as","much","shape","information","as","you","can","!","See","also","`","testInputShapeChecks","`","for","more","on","what","shape","checking","can","accomplish","when","only","partial","shape","information","is","available","."]
code: def testFullShapeAvailableAtRuntimeOnly(self):
      """What happens when shape information isn't available statically?
  
      The short answer is: it still works. The long answer is: it still works, but
      arguments that shouldn't work due to argument shape mismatch can sometimes
      work without raising any errors! This can cause insidious bugs. This test
      verifies correct behaviour and also demonstrates kinds of shape mismatch
      that can go undetected. Look for `!!!DANGER!!!` below.
  
      Why this is possible: internally, `batched_index` flattens its inputs,
      then transforms the action indices you provide into indices into its
      flattened Q values tensor. So long as these flattened indices don't go
      out-of-bounds, and so long as your arguments are compatible with a few
      other bookkeeping operations, the operation will succeed.
  
      The moral: always provide as much shape information as you can! See also
      `testInputShapeChecks` for more on what shape checking can accomplish when
      only partial shape information is available.
      """
  
      ## 1. No shape information is available during construction time.
      q_values = tf.placeholder(tf.float32)
      actions = tf.placeholder(tf.int32)
      values = indexing_ops.batched_index(q_values, actions)
  
      with self.test_session() as sess:
          # First, correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [51],
              sess.run(
                  values, feed_dict={q_values: [[50, 51]], actions: [1]}
              ),
          )
          self.assertAllClose(
              [[51, 52]],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [[[50, 51], [52, 53]]],
                      actions: [[1, 0]],
                  },
              ),
          )
  
          # !!!DANGER!!! These "incompatible" shapes are silently tolerated!
          # (These examples are probably not exhaustive, either!)
          qs_2x2 = [[5, 5], [5, 5]]
          qs_2x2x2 = [[[5, 5], [5, 5]], [[5, 5], [5, 5]]]
          sess.run(values, feed_dict={q_values: qs_2x2, actions: [0]})
          sess.run(values, feed_dict={q_values: qs_2x2, actions: 0})
          sess.run(
              values, feed_dict={q_values: qs_2x2x2, actions: [[0]]}
          )
          sess.run(values, feed_dict={q_values: qs_2x2x2, actions: [0]})
          sess.run(values, feed_dict={q_values: qs_2x2x2, actions: 0})
  
      ## 2a. Shape information is only known for the batch size (2-D case).
      q_values = tf.placeholder(tf.float32, shape=[2, None])
      actions = tf.placeholder(tf.int32, shape=[2])
      values = indexing_ops.batched_index(q_values, actions)
      with self.test_session() as sess:
          # Correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [51, 52],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [[50, 51], [52, 53]],
                      actions: [1, 0],
                  },
              ),
          )
          # There are no really terrible shape errors that go uncaught in this case.
  
      ## 2b. Shape information is only known for the batch size (3-D case).
      q_values = tf.placeholder(tf.float32, shape=[None, 2, None])
      actions = tf.placeholder(tf.int32, shape=[None, 2])
      values = indexing_ops.batched_index(q_values, actions)
      with self.test_session() as sess:
          # Correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [[51, 52]],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [[[50, 51], [52, 53]]],
                      actions: [[1, 0]],
                  },
              ),
          )
  
          # !!!DANGER!!! This "incompatible" shape is silently tolerated!
          sess.run(
              values, feed_dict={q_values: qs_2x2x2, actions: [[0, 0]]}
          )
  
      ## 3. Shape information is only known for the sequence length.
      q_values = tf.placeholder(tf.float32, shape=[2, None, None])
      actions = tf.placeholder(tf.int32, shape=[2, None])
      values = indexing_ops.batched_index(q_values, actions)
      with self.test_session() as sess:
          # Correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [[51, 52], [54, 57]],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [
                          [[50, 51], [52, 53]],
                          [[54, 55], [56, 57]],
                      ],
                      actions: [[1, 0], [0, 1]],
                  },
              ),
          )
  
          # !!!DANGER!!! This "incompatible" shape is silently tolerated!
          sess.run(
              values,
              feed_dict={q_values: qs_2x2x2, actions: [[0], [0]]},
          )
  
      ## 4a. Shape information is only known for the number of actions (2-D case).
      q_values = tf.placeholder(tf.float32, shape=[None, 2])
      actions = tf.placeholder(tf.int32, shape=[None])
      values = indexing_ops.batched_index(q_values, actions)
      with self.test_session() as sess:
          # Correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [51, 52],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [[50, 51], [52, 53]],
                      actions: [1, 0],
                  },
              ),
          )
  
          # !!!DANGER!!! This "incompatible" shape is silently tolerated!
          sess.run(values, feed_dict={q_values: qs_2x2, actions: [0]})
  
      ## 4b. Shape information is only known for the number of actions (3-D case).
      q_values = tf.placeholder(tf.float32, shape=[None, None, 2])
      actions = tf.placeholder(tf.int32, shape=[None, None])
      values = indexing_ops.batched_index(q_values, actions)
      with self.test_session() as sess:
          # Correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [[51, 52]],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [[[50, 51], [52, 53]]],
                      actions: [[1, 0]],
                  },
              ),
          )
  
          # !!!DANGER!!! These "incompatible" shapes are silently tolerated!
          sess.run(
              values, feed_dict={q_values: qs_2x2x2, actions: [[0, 0]]}
          )
          sess.run(
              values, feed_dict={q_values: qs_2x2x2, actions: [[0]]}
          )
  
      ## 5a. Value shape is not known ahead of time.
      q_values = tf.placeholder(tf.float32)
      actions = tf.placeholder(tf.int32, shape=[2])
      values = indexing_ops.batched_index(q_values, actions)
      with self.test_session() as sess:
          # Correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [51, 52],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [[50, 51], [52, 53]],
                      actions: [1, 0],
                  },
              ),
          )
  
          # !!!DANGER!!! This "incompatible" shape is silently tolerated!
          sess.run(
              values, feed_dict={q_values: qs_2x2x2, actions: [0, 0]}
          )
  
      ## 5b. Action shape is not known ahead of time.
      q_values = tf.placeholder(tf.float32, shape=[None, None, 2])
      actions = tf.placeholder(tf.int32)
      values = indexing_ops.batched_index(q_values, actions)
      with self.test_session() as sess:
          # Correct and compatible Q values and indices work as intended.
          self.assertAllClose(
              [[51, 52], [54, 57]],
              sess.run(
                  values,
                  feed_dict={
                      q_values: [
                          [[50, 51], [52, 53]],
                          [[54, 55], [56, 57]],
                      ],
                      actions: [[1, 0], [0, 1]],
                  },
              ),
          )
  
          # !!!DANGER!!! This "incompatible" shape is silently tolerated!
          sess.run(
              values, feed_dict={q_values: qs_2x2x2, actions: [0, 0]}
          )
  
file_path: trfl/trfl/indexing_ops_test.py
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from absl.testing import parameterized
  import numpy
  import tensorflow.compat.v1
  from trfl import indexing_ops
label_desc: Use image node_id 4 for calling the BatchIndexingTest obj's underlying member method code with example usage: obj.testFullShapeAvailableAtRuntimeOnly() without return types