Skip to content
Permalink
Browse files

Make Expression support comparison operators. (#4962)

* make Expression support comparison operators.

* add type check in comparison methods.

* extract common method for comparison operators.
  • Loading branch information...
tongda authored and danking committed Dec 14, 2018
1 parent a044911 commit 542d6bd09281b90bd4fae3e8e5704abc7c422af3
Showing with 40 additions and 18 deletions.
  1. +15 −16 hail/python/hail/expr/expressions/base_expression.py
  2. +25 −2 hail/python/test/hail/expr/test_expr.py
@@ -339,16 +339,16 @@ def describe(self, handler=print):
handler(s)

def __lt__(self, other):
raise NotImplementedError("'<' comparison with expression of type {}".format(str(self._type)))
return self._compare_op("<", other)

def __le__(self, other):
raise NotImplementedError("'<=' comparison with expression of type {}".format(str(self._type)))
return self._compare_op("<=", other)

def __gt__(self, other):
raise NotImplementedError("'>' comparison with expression of type {}".format(str(self._type)))
return self._compare_op(">", other)

def __ge__(self, other):
raise NotImplementedError("'>=' comparison with expression of type {}".format(str(self._type)))
return self._compare_op(">=", other)

def __nonzero__(self):
raise ExpressionException(
@@ -360,6 +360,15 @@ def __nonzero__(self):
def __iter__(self):
raise ExpressionException(f"{repr(self)} object is not iterable")

def _compare_op(self, op, other):
other = to_expr(other)
left, right, success = unify_exprs(self, other)
if not success:
raise TypeError(f"Invalid '{op}' comparison, cannot compare expressions "
f"of type '{self.dtype}' and '{other.dtype}'")
res = left._bin_op(op, right, hl.tbool)
return res

def _is_scalar(self):
return self._indices.source is None

@@ -531,12 +540,7 @@ def __eq__(self, other):
:class:`.BooleanExpression`
``True`` if the two expressions are equal.
"""
other = to_expr(other)
left, right, success = unify_exprs(self, other)
if not success:
raise TypeError(f"Invalid '==' comparison, cannot compare expressions "
f"of type '{self.dtype}' and '{other.dtype}'")
return left._bin_op("==", right, tbool)
return self._compare_op("==", other)

def __ne__(self, other):
"""Returns ``True`` if the two expressions are not equal.
@@ -569,12 +573,7 @@ def __ne__(self, other):
:class:`.BooleanExpression`
``True`` if the two expressions are not equal.
"""
other = to_expr(other)
left, right, success = unify_exprs(self, other)
if not success:
raise TypeError(f"Invalid '!=' comparison, cannot compare expressions "
f"of type '{self.dtype}' and '{other.dtype}'")
return left._bin_op("!=", right, tbool)
return self._compare_op("!=", other)

def _to_table(self, name):
source = self._indices.source
@@ -101,7 +101,24 @@ def test_operators(self):
x33=(kt.a == 0) & (kt.b == 5),
x34=(kt.a == 0) | (kt.b == 5),
x35=False,
x36=True
x36=True,
x37=kt.e > "helln",
x38=kt.e < "hellp",
x39=kt.e <= "hello",
x40=kt.e >= "hello",
x41="helln" > kt.e,
x42="hellp" < kt.e,
x43="hello" >= kt.e,
x44="hello" <= kt.e,
x45=kt.f > [1, 2],
x46=kt.f < [1, 3],
x47=kt.f >= [1, 2, 3],
x48=kt.f <= [1, 2, 3],
x49=kt.f < [1.0, 2.0],
x50=kt.f > [1.0, 3.0],
x51=[1.0, 2.0, 3.0] <= kt.f,
x52=[1.0, 2.0, 3.0] >= kt.f,
x53=hl.tuple([True, 1.0]) < (1.0, 0.0),
).take(1)[0])

expected = {'a': 4, 'b': 1, 'c': 3, 'd': 5, 'e': "hello", 'f': [1, 2, 3],
@@ -115,7 +132,13 @@ def test_operators(self):
'x24': True, 'x25': False, 'x26': True,
'x27': False, 'x28': True, 'x29': False,
'x30': False, 'x31': True, 'x32': False,
'x33': False, 'x34': False, 'x35': False, 'x36': True}
'x33': False, 'x34': False, 'x35': False,
'x36': True, 'x37': True, 'x38': True,
'x39': True, 'x40': True, 'x41': False,
'x42': False, 'x43': True, 'x44': True,
'x45': True, 'x46': True, 'x47': True,
'x48': True, 'x49': False, 'x50': False,
'x51': True, 'x52': True, 'x53': False}

for k, v in expected.items():
if isinstance(v, float):

0 comments on commit 542d6bd

Please sign in to comment.
You can’t perform that action at this time.