1# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Logical boolean operators: not, and, or."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21from tensorflow.python.framework import tensor_util
22from tensorflow.python.ops import control_flow_ops
23from tensorflow.python.ops import gen_math_ops
24
25
26def not_(a):
27  """Functional form of "not"."""
28  if tensor_util.is_tf_type(a):
29    return _tf_not(a)
30  return _py_not(a)
31
32
33def _tf_not(a):
34  """Implementation of the "not_" operator for TensorFlow."""
35  return gen_math_ops.logical_not(a)
36
37
38def _py_not(a):
39  """Default Python implementation of the "not_" operator."""
40  return not a
41
42
43def and_(a, b):
44  """Functional form of "and". Uses lazy evaluation semantics."""
45  a_val = a()
46  if tensor_util.is_tf_type(a_val):
47    return _tf_lazy_and(a_val, b)
48  return _py_lazy_and(a_val, b)
49
50
51def _tf_lazy_and(cond, b):
52  """Lazy-eval equivalent of "and" for Tensors."""
53  # TODO(mdan): Enforce cond is scalar here?
54  return control_flow_ops.cond(cond, b, lambda: cond)
55
56
57def _py_lazy_and(cond, b):
58  """Lazy-eval equivalent of "and" in Python."""
59  return cond and b()
60
61
62def or_(a, b):
63  """Functional form of "or". Uses lazy evaluation semantics."""
64  a_val = a()
65  if tensor_util.is_tf_type(a_val):
66    return _tf_lazy_or(a_val, b)
67  return _py_lazy_or(a_val, b)
68
69
70def _tf_lazy_or(cond, b):
71  """Lazy-eval equivalent of "or" for Tensors."""
72  # TODO(mdan): Enforce cond is scalar here?
73  return control_flow_ops.cond(cond, lambda: cond, b)
74
75
76def _py_lazy_or(cond, b):
77  """Lazy-eval equivalent of "or" in Python."""
78  return cond or b()
79
80
81def eq(a, b):
82  """Functional form of "equal"."""
83  if tensor_util.is_tf_type(a) or tensor_util.is_tf_type(b):
84    return _tf_equal(a, b)
85  return _py_equal(a, b)
86
87
88def _tf_equal(a, b):
89  """Overload of "equal" for Tensors."""
90  return gen_math_ops.equal(a, b)
91
92
93def _py_equal(a, b):
94  """Overload of "equal" that falls back to Python's default implementation."""
95  return a == b
96
97
98def not_eq(a, b):
99  """Functional form of "not-equal"."""
100  return not_(eq(a, b))
101