Functional form of a while statement. The loop operates on a so-called state, which includes all symbols that are variant across loop iterations. In what follows we refer to state as either a tuple of entities that represent an actual state, or a list of arguments of the corresponding types
(
test,
body,
get_state,
set_state,
init_vars,
basic_symbol_names=None,
composite_symbol_names=None,
opts=None,
)
| 673 | |
| 674 | |
| 675 | def while_stmt( |
| 676 | test, |
| 677 | body, |
| 678 | get_state, |
| 679 | set_state, |
| 680 | init_vars, |
| 681 | basic_symbol_names=None, |
| 682 | composite_symbol_names=None, |
| 683 | opts=None, |
| 684 | ): |
| 685 | """Functional form of a while statement. |
| 686 | |
| 687 | The loop operates on a so-called state, which includes all symbols that are |
| 688 | variant across loop iterations. In what follows we refer to state as either |
| 689 | a tuple of entities that represent an actual state, or a list of arguments |
| 690 | of the corresponding types. |
| 691 | |
| 692 | Args: |
| 693 | test: Callable with the state as arguments, and boolean return type. The |
| 694 | loop condition. |
| 695 | body: Callable with the state as arguments, and state as return type. The |
| 696 | actual loop body. |
| 697 | get_state: Additional callable which can capture additional state (such as |
| 698 | the values of composite symbols). This is only useful when staging the |
| 699 | loop. |
| 700 | set_state: Additional callable which save values captured by get_state back |
| 701 | into the Python environment. This is only useful when staging the loop. |
| 702 | init_vars: Tuple containing the initial state. |
| 703 | basic_symbol_names: Tuple containing basic loop var names. |
| 704 | composite_symbol_names: Tuple containing composite loop var names. |
| 705 | opts: Optional dict of extra loop parameters. |
| 706 | |
| 707 | Returns: |
| 708 | Tuple containing the final state. |
| 709 | """ |
| 710 | |
| 711 | # Evaluate the initial test once in order to do the dispatch. The evaluation |
| 712 | # is isolated to minimize unwanted side effects. |
| 713 | # TODO(mdan): Do a full iteration - some state types might lower to Tensor. |
| 714 | with func_graph.FuncGraph('tmp').as_default(): |
| 715 | init_test = test(*init_vars) |
| 716 | |
| 717 | # TensorFlow: Multiple evaluations are acceptable in this case, so we're fine |
| 718 | # with the re-evaluation of `test` that `_tf_while_stmt` will make. |
| 719 | if tensors.is_dense_tensor(init_test): |
| 720 | return _tf_while_stmt(test, body, get_state, set_state, init_vars, |
| 721 | basic_symbol_names, composite_symbol_names, opts) |
| 722 | |
| 723 | # Normal Python: We already consumed one evaluation of `test`; consistently, |
| 724 | # unroll one iteration before dispatching to a normal loop. |
| 725 | # TODO(mdan): Push the "init_test" value via opts into _py_while_stmt? |
| 726 | if not init_test: |
| 727 | return init_vars |
| 728 | init_vars = body(*init_vars) |
| 729 | |
| 730 | return _py_while_stmt(test, body, get_state, set_state, init_vars, opts) |
| 731 | |
| 732 |
nothing calls this directly
no test coverage detected