Skip to content

Commit

Permalink
Added std, var and corr operations.
Browse files Browse the repository at this point in the history
  • Loading branch information
xmnlab committed Apr 13, 2018
1 parent 120efaa commit 4061ea0
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 22 deletions.
1 change: 1 addition & 0 deletions ibis/mapd/api.py
@@ -1,6 +1,7 @@
from ibis.config import options
from ibis.mapd.compiler import dialect, compiles, rewrites
from ibis.mapd.client import MapDClient
from ibis.mapd.operations import pi

import ibis.common as com

Expand Down
60 changes: 59 additions & 1 deletion ibis/mapd/compiler.py
Expand Up @@ -3,10 +3,11 @@
import ibis.common as com
import ibis.util as util
import ibis.expr.operations as ops
import ibis.expr.types as ir
import ibis.sql.compiler as compiles

from .operations import (
_operation_registry, _name_expr, _trigonometric_ops
_operation_registry, _name_expr, Corr
)


Expand Down Expand Up @@ -194,3 +195,60 @@ class MapDDialect(compiles.Dialect):
dialect = MapDDialect
compiles = MapDExprTranslator.compiles
rewrites = MapDExprTranslator.rewrites


@compiles(ops.StandardDev)
def compile_std(translator, expr):
# pull out the arguments to the expression
args = expr.op().args
args_size = len(args)

x = args[0]
how = '' if args_size < 2 else '_%s' % args[1].upper()[:4]

f_type = '' if isinstance(x, ir.IntegerColumn) else '_FLOAT'

# compile the argument
compiled_arg = translator.translate(x)

return 'STDDEV%s%s(%s)' % (how, f_type, compiled_arg)


@compiles(ops.Variance)
def compile_var(translator, expr):
# pull out the arguments to the expression
args = expr.op().args
args_size = len(args)

x = args[0]
how = '' if args_size < 2 else '_%s' % args[1].upper()[:4]

if how == '':
f_name = 'VARIANCE'
else:
f_name = 'VAR'

f_type = '' if isinstance(x, ir.IntegerColumn) else '_FLOAT'

# compile the argument
compiled_arg = translator.translate(x)

return '%s%s%s(%s)' % (f_name, how, f_type, compiled_arg)


@compiles(Corr)
def compile_corr(translator, expr):
# pull out the arguments to the expression
args = expr.op().args

x, y = args

f_type = ''
if isinstance(x, ir.FloatingColumn) or isinstance(y, ir.FloatingColumn):
f_type = '_FLOAT'

# compile the argument
compiled_x = translator.translate(x)
compiled_y = translator.translate(y)

return 'CORR%s(%s, %s)' % (f_type, compiled_x, compiled_y)
1 change: 1 addition & 0 deletions ibis/mapd/identifiers.py
Expand Up @@ -250,6 +250,7 @@
'varchar',
})

# @TODO: check if it is necessary
_ibis = frozenset({
'literal'
})
Expand Down
53 changes: 32 additions & 21 deletions ibis/mapd/operations.py
Expand Up @@ -12,6 +12,10 @@
from ibis.expr.types import NumericValue, StringValue


def pi_compile():
return 'pi()'


def _cast(translator, expr):
from ibis.mapd.client import MapDDataType

Expand Down Expand Up @@ -507,12 +511,15 @@ class Degrees(ops.UnaryOp):
output_type = rlz.shape_like('arg', ops.dt.float)


class PI(ops.Constant):
class PI(ops.ValueOp):
"""Converts radians to degrees"""
def output_type(self):
return ops.dt.float64.scalar_type()


pi = PI()


class Log(ops.Ln):
"""
Expand Down Expand Up @@ -547,21 +554,21 @@ class Truncate(ops.NumericBinaryOp):

# STATS
"""
class Correlation(x, y) CORRELATION_FLOAT(x, y) Alias of CORR. Returns the coefficient of correlation of a set of number pairs.
class CORR(x, y) CORR_FLOAT(x, y) Returns the coefficient of correlation of a set of number pairs.
class COVAR_POP(x, y) COVAR_POP_FLOAT(x, y) Returns the population covariance of a set of number pairs.
class COVAR_SAMP(x, y) COVAR_SAMP_FLOAT(x, y) Returns the sample covariance of a set of number pairs.
ops.StandardDev: agg_variance_like('stddev'),
# STDDEV(x) STDDEV_FLOAT(x) Alias of STDDEV_SAMP. Returns sample standard deviation of the value.
# STDDEV_POP(x) STDDEV_POP_FLOAT(x) Returns the population standard the standard deviation of the value.
# STDDEV_SAMP(x) STDDEV_SAMP_FLOAT(x) Returns the sample standard deviation of the value.
ops.Variance: agg_variance_like('var'),
# VARIANCE(x) VARIANCE_FLOAT(x) Alias of VAR_SAMP. Returns the sample variance of the value.
# VAR_POP(x) VAR_POP_FLOAT(x) Returns the population variance sample variance of the value.
# VAR_SAMP(x) VAR_SAMP_FLOAT(x) Returns the sample variance of the value.
"""


class Corr(ops.BinaryOp):
"""
Returns the coefficient of correlation of a set of number pairs.
"""
x = ops.Arg(rlz.numeric)
y = ops.Arg(rlz.numeric)
output_type = rlz.shape_like('x', ops.dt.float)


# TRIGONOMETRY

class TrigonometryUnary(ops.UnaryOp):
Expand Down Expand Up @@ -705,18 +712,11 @@ class StringLengthBytes(ops.UnaryOp):
}

_stats_ops = {
# CORRELATION(x, y) CORRELATION_FLOAT(x, y) Alias of CORR. Returns the coefficient of correlation of a set of number pairs.
# CORR(x, y) CORR_FLOAT(x, y) Returns the coefficient of correlation of a set of number pairs.
Corr: fixed_arity('corr', 2),
# COVAR_POP(x, y) COVAR_POP_FLOAT(x, y) Returns the population covariance of a set of number pairs.
# COVAR_SAMP(x, y) COVAR_SAMP_FLOAT(x, y) Returns the sample covariance of a set of number pairs.
ops.StandardDev: agg_variance_like('stddev'),
# STDDEV(x) STDDEV_FLOAT(x) Alias of STDDEV_SAMP. Returns sample standard deviation of the value.
# STDDEV_POP(x) STDDEV_POP_FLOAT(x) Returns the population standard the standard deviation of the value.
# STDDEV_SAMP(x) STDDEV_SAMP_FLOAT(x) Returns the sample standard deviation of the value.
ops.Variance: agg_variance_like('var'),
# VARIANCE(x) VARIANCE_FLOAT(x) Alias of VAR_SAMP. Returns the sample variance of the value.
# VAR_POP(x) VAR_POP_FLOAT(x) Returns the population variance sample variance of the value.
# VAR_SAMP(x) VAR_SAMP_FLOAT(x) Returns the sample variance of the value.
}


Expand Down Expand Up @@ -824,14 +824,24 @@ class StringLengthBytes(ops.UnaryOp):


def assign_function_to_dtype(dtype, function_ops: dict):
# generate trigonometric function for NumericValue class
"""
:param dtype:
:param function_ops:
:return:
"""
for klass in function_ops.keys():
# skip if the class is already in the ibis operations
if klass in ops.__dict__.values():
continue

def f(_klass):
"""
Return a lambda function that return to_expr() result from the
custom classes.
"""
return lambda *args: _klass(*args).to_expr()
# assign new function to the defined DataType
setattr(
dtype, klass.__name__.lower(), f(klass)
)
Expand All @@ -840,4 +850,5 @@ def f(_klass):
assign_function_to_dtype(NumericValue, _trigonometric_ops)
assign_function_to_dtype(NumericValue, _math_ops)
assign_function_to_dtype(StringValue, _string_ops)
assign_function_to_dtype(NumericValue, _geometric_ops)
assign_function_to_dtype(NumericValue, _geometric_ops)
assign_function_to_dtype(NumericValue, _stats_ops)
5 changes: 5 additions & 0 deletions ibis/mapd/udf.py
@@ -0,0 +1,5 @@
"""
User Defined Function
@see http://docs.ibis-project.org/udf.html
"""

0 comments on commit 4061ea0

Please sign in to comment.