class_docstr: Test case that backend implementations can extend.
docstr: Check that the `test_var_type` gives the same results as `ModelVariable`.
  
  This is a model-based property test: For any initialization and
  any sequence of variable operations (read, update, push, pop), the
  implementation under test should behave the same as the model.
  
  By "behave the same", we mean that:
  
  - Neither the model nor the testee throw exceptions other than
    `ValueError`
  
  - Any operation that causes the model to throw `ValueError` also
    causes the testee to throw `ValueError` (alt. one of the errors in
    `exception_types`), and the testee does not throw otherwise
  
  - The result of reading from the model and from the testee is the
    same after any (sub-)sequence of operations, except where the
    model indicates that the result of a read is (partially)
    undefined.
  
  Args:
    init: Tuple of max_stack_depth and batched initial value
    ops: Sequence of operations to test. Each op is a tuple of a string,
        one of 'read', 'update', 'push', or 'pop', followed by the relevant
        number of arguments.
    test_var_initter: Callable taking init args (max_stack_depth,
      initial_value) and returning the a Variable object to test.
    to_numpy_arrays: Optional mapper from read results (or tuples thereof) to
        numpy `array`.
    exception_types: Exception classes to catch.
code: def check_same_results(
      self,
      init,
      ops,
      test_var_initter,
      to_numpy_arrays=lambda x: x,
      exception_types=ValueError,
  ):
      """Check that the `test_var_type` gives the same results as `ModelVariable`.
  
      This is a model-based property test: For any initialization and
      any sequence of variable operations (read, update, push, pop), the
      implementation under test should behave the same as the model.
  
      By "behave the same", we mean that:
  
      - Neither the model nor the testee throw exceptions other than
        `ValueError`
  
      - Any operation that causes the model to throw `ValueError` also
        causes the testee to throw `ValueError` (alt. one of the errors in
        `exception_types`), and the testee does not throw otherwise
  
      - The result of reading from the model and from the testee is the
        same after any (sub-)sequence of operations, except where the
        model indicates that the result of a read is (partially)
        undefined.
  
      Args:
        init: Tuple of max_stack_depth and batched initial value
        ops: Sequence of operations to test. Each op is a tuple of a string,
            one of 'read', 'update', 'push', or 'pop', followed by the relevant
            number of arguments.
        test_var_initter: Callable taking init args (max_stack_depth,
          initial_value) and returning the a Variable object to test.
        to_numpy_arrays: Optional mapper from read results (or tuples thereof) to
            numpy `array`.
        exception_types: Exception classes to catch.
      """
      model_var = create_model_variable(*init)
      test_var = test_var_initter(*init)
      logging.info("Init: %s", init)
  
      def check_read_agrees():
          """Assert that the model var and the var under test agree on read."""
          model_res = model_var.read()
          test_res = to_numpy_arrays(test_var.read())
          assert len(model_res) == len(test_res)
          logging.vlog(
              1, "Internal state: %s", to_numpy_arrays(test_var)
          )
          for i, (m, t) in enumerate(zip(model_res, test_res)):
              if m is not None:
                  self.assertAllEqual(
                      m, t, msg="Batch member {} disagrees".format(i)
                  )
  
      check_read_agrees()
      for op in ops:
          type_ = op[0]
          args = op[1:]
          logging.info("Executing %s: %s", type_, args)
          if type_ == "read":
              check_read_agrees()
          elif type_ == "update":
              assert len(args) == 2
              model_var = model_var.update(*args)
              test_var = test_var.update(*args)
              check_read_agrees()
          elif type_ == "push":
              assert len(args) == 1
              try:
                  model_var = model_var.push(*args)
              except ValueError:
                  logging.info("push fails")
                  with self.assertRaises(exception_types):
                      to_numpy_arrays(test_var.push(*args).read())
              else:  # If the model pushed without raising
                  test_var = test_var.push(*args)
              check_read_agrees()
          elif type_ == "pop":
              assert len(args) == 1
              try:
                  model_var = model_var.pop(*args)
              except ValueError:
                  logging.info("pop fails")
                  with self.assertRaises(exception_types):
                      to_numpy_arrays(test_var.pop(*args).read())
              else:  # If the model popped without raising
                  test_var = test_var.pop(*args)
              check_read_agrees()
          else:
              assert False, "Invalid op type"
  
file_path: probability/tensorflow_probability/python/experimental/auto_batching/backend_test_lib.py
imports: from absl import logging
label_desc: Use image node_id 1 for calling the VariableTestCase obj's underlying member method code with example usage: obj.check_same_results(init, ops, test_var_initter, to_numpy_arrays, exception_types) without return types