def _check_preconditions(self,
            state: Sequence[tf.Tensor],
            action: Sequence[tf.Tensor],
            bound_constraints: Dict[str, Constraints],
            default: Sequence[tf.Tensor]) -> Tuple[tf.Tensor, Sequence[tf.Tensor], tf.Tensor]:
        '''Samples action fluents until all preconditions are satisfied.

        Checks action preconditions for the sampled `action` and current `state`,
        and iff all preconditions are satisfied it returns the sampled action fluents.

        Args:
            state (Sequence[tf.Tensor]): A list of state fluents.
            action (Sequence[tf.Tensor]): A list of action fluents.
            bound_constraints (Dict[str, Tuple[Optional[TensorFluent], Optional[TensorFluent]]]): The bounds for each action fluent.
            default (Sequence[tf.Tensor]): The default action fluents.

        Returns:
            Tuple[tf.Tensor, Sequence[tf.Tensor], tf.Tensor]: A tuple with
            an integer tensor corresponding to the number of samples,
            action fluents and a boolean tensor for checking all action preconditions.
        '''

        def condition(i, a, checking):
            not_checking = tf.reduce_any(tf.logical_not(checking))
            return not_checking

        def body(i, a, checking):
            new_action = []
            new_sampled_action = self._sample_action(bound_constraints, default)
            new_preconds_checking = self.compiler.compile_action_preconditions_checking(state, new_sampled_action)
            for action_fluent, new_sampled_action_fluent in zip(a, new_sampled_action):
                new_action_fluent = tf.where(checking, action_fluent, new_sampled_action_fluent)
                new_action.append(new_action_fluent)
            new_action = tuple(new_action)
            new_checking = tf.logical_or(checking, new_preconds_checking)
            return (i + 1, new_action, new_checking)

        i0 = tf.constant(0)
        preconds_checking = self.compiler.compile_action_preconditions_checking(state, action)
        return tf.while_loop(condition, body, loop_vars=[i0, action, preconds_checking])
Samples action fluents until all preconditions are satisfied.

        Checks action preconditions for the sampled `action` and current `state`,
        and iff all preconditions are satisfied it returns the sampled action fluents.

        Args:
            state (Sequence[tf.Tensor]): A list of state fluents.
            action (Sequence[tf.Tensor]): A list of action fluents.
            bound_constraints (Dict[str, Tuple[Optional[TensorFluent], Optional[TensorFluent]]]): The bounds for each action fluent.
            default (Sequence[tf.Tensor]): The default action fluents.

        Returns:
            Tuple[tf.Tensor, Sequence[tf.Tensor], tf.Tensor]: A tuple with
            an integer tensor corresponding to the number of samples,
            action fluents and a boolean tensor for checking all action preconditions.