Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ==, !=, >, <, and string equality computed columns #957

Merged
merged 3 commits into from
Mar 6, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions cpp/perspective/src/cpp/computed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ t_computed_column::get_computed_function_1(t_computation computation) {
case MULTIPLY: return computed_function::multiply<DTYPE>; \
case DIVIDE: return computed_function::divide<DTYPE>; \
case PERCENT_A_OF_B: return computed_function::percent_of<DTYPE>; \
case EQUALS: return computed_function::equals<DTYPE>; \
case NOT_EQUALS: return computed_function::not_equals<DTYPE>; \
case GREATER_THAN: return computed_function::greater_than<DTYPE>; \
case LESS_THAN: return computed_function::less_than<DTYPE>; \
default: break; \
}

Expand Down Expand Up @@ -152,6 +156,12 @@ t_computed_column::get_computed_function_2(t_computation computation) {
case DTYPE_FLOAT64: {
GET_COMPUTED_FUNCTION_2(DTYPE_FLOAT64);
} break;
case DTYPE_STR: {
switch (computation.m_name) {
case IS: return computed_function::is;
default: break;
}
}
default: break;
}

Expand Down Expand Up @@ -302,6 +312,7 @@ void t_computed_column::make_computations() {
std::vector<t_dtype> dtypes = {DTYPE_FLOAT64, DTYPE_FLOAT32, DTYPE_INT64, DTYPE_INT32, DTYPE_INT16, DTYPE_INT8, DTYPE_UINT64, DTYPE_UINT32, DTYPE_UINT16, DTYPE_UINT8};
std::vector<t_computed_function_name> numeric_function_1 = {INVERT, POW, SQRT, ABS, BUCKET_10, BUCKET_100, BUCKET_1000, BUCKET_0_1, BUCKET_0_0_1, BUCKET_0_0_0_1};
std::vector<t_computed_function_name> numeric_function_2 = {ADD, SUBTRACT, MULTIPLY, DIVIDE, PERCENT_A_OF_B};
std::vector<t_computed_function_name> numeric_comparison_2 = {EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN};

for (const auto f : numeric_function_1) {
for (auto i = 0; i < dtypes.size(); ++i) {
Expand Down Expand Up @@ -329,6 +340,20 @@ void t_computed_column::make_computations() {
}
}

for (const auto f : numeric_comparison_2) {
for (auto i = 0; i < dtypes.size(); ++i) {
for (auto j = 0; j < dtypes.size(); ++j) {
t_computed_column::computations.push_back(
t_computation{
f,
std::vector<t_dtype>{dtypes[i], dtypes[j]},
DTYPE_BOOL
}
);
}
}
}

// Generate string functions
std::vector<t_computed_function_name> string_function_1 = {UPPERCASE, LOWERCASE};
std::vector<t_computed_function_name> string_function_2 = {CONCAT_SPACE, CONCAT_COMMA};
Expand Down Expand Up @@ -358,6 +383,11 @@ void t_computed_column::make_computations() {
t_computation{LENGTH, std::vector<t_dtype>{DTYPE_STR}, DTYPE_INT64}
);

// IS takes 2 strings and returns a bool
t_computed_column::computations.push_back(
t_computation{IS, std::vector<t_dtype>{DTYPE_STR, DTYPE_STR}, DTYPE_BOOL}
);

// Generate date/datetime functions
std::vector<t_dtype> date_dtypes = {DTYPE_DATE, DTYPE_TIME};

Expand Down
70 changes: 70 additions & 0 deletions cpp/perspective/src/cpp/computed_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,62 @@ NUMERIC_FUNCTION_1(BUCKET_0_0_0_1);
return rval; \
}

#define EQUALS(T1, T2) \
t_tscalar equals_##T1##_##T2(t_tscalar x, t_tscalar y) { \
t_tscalar rval; \
rval.set(false); \
if ((x.is_none() || !x.is_valid()) \
&& (y.is_none() || !y.is_valid())) { \
rval.set(true); \
return rval; \
} else if ((x.is_none() || !x.is_valid()) \
|| (y.is_none() || !y.is_valid())) { \
rval.set(false); \
return rval; \
} \
rval.set(static_cast<bool>(x.get<T1>() == y.get<T2>())); \
return rval; \
}

#define NOT_EQUALS(T1, T2) \
t_tscalar not_equals_##T1##_##T2(t_tscalar x, t_tscalar y) { \
t_tscalar rval; \
rval.set(false); \
if ((x.is_none() || !x.is_valid()) \
|| (y.is_none() || !y.is_valid())) return rval; \
rval.set(static_cast<bool>(x.get<T1>() != y.get<T2>())); \
return rval; \
}

#define GREATER_THAN(T1, T2) \
t_tscalar greater_than_##T1##_##T2(t_tscalar x, t_tscalar y) { \
t_tscalar rval; \
rval.set(false); \
if ((x.is_none() || !x.is_valid()) \
|| (y.is_none() || !y.is_valid())) return rval; \
rval.set(static_cast<bool>(x.get<T1>() > y.get<T2>())); \
return rval; \
}

#define LESS_THAN(T1, T2) \
t_tscalar less_than_##T1##_##T2(t_tscalar x, t_tscalar y) { \
t_tscalar rval; \
rval.set(false); \
if ((x.is_none() || !x.is_valid()) \
|| (y.is_none() || !y.is_valid())) return rval; \
rval.set(static_cast<bool>(x.get<T1>() < y.get<T2>())); \
return rval; \
}

NUMERIC_FUNCTION_2(ADD);
NUMERIC_FUNCTION_2(SUBTRACT);
NUMERIC_FUNCTION_2(MULTIPLY);
NUMERIC_FUNCTION_2(DIVIDE);
NUMERIC_FUNCTION_2(PERCENT_OF);
NUMERIC_FUNCTION_2(EQUALS);
NUMERIC_FUNCTION_2(NOT_EQUALS);
NUMERIC_FUNCTION_2(GREATER_THAN);
NUMERIC_FUNCTION_2(LESS_THAN);

/**
* @brief Generate dispatch functions that call the correct computation method
Expand Down Expand Up @@ -351,6 +402,10 @@ NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(subtract);
NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(multiply);
NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(divide);
NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(percent_of);
NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(equals);
NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(not_equals);
NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(greater_than);
NUMERIC_FUNCTION_2_DISPATCH_ALL_TYPES(less_than);

// String functions
t_tscalar length(t_tscalar x) {
Expand All @@ -365,6 +420,21 @@ t_tscalar length(t_tscalar x) {
return rval;
}

t_tscalar is(t_tscalar x, t_tscalar y) {
t_tscalar rval;
rval.set(false);

if ((x.is_none() || !x.is_valid() || x.get_dtype() != DTYPE_STR)
|| (y.is_none() || !y.is_valid() || y.get_dtype() != DTYPE_STR)) {
return rval;
}

std::string x_str = x.to_string();
std::string y_str = y.to_string();
rval.set(x_str == y_str);
sc1f marked this conversation as resolved.
Show resolved Hide resolved
return rval;
}

void uppercase(t_tscalar x, std::int32_t idx, std::shared_ptr<t_column> output_column) {
if (x.is_none() || !x.is_valid() || x.get_dtype() != DTYPE_STR) {
output_column->set_scalar(idx, mknone());
Expand Down
5 changes: 5 additions & 0 deletions cpp/perspective/src/cpp/emscripten.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2007,9 +2007,14 @@ EMSCRIPTEN_BINDINGS(perspective) {
.value("SQRT", SQRT)
.value("ABS", ABS)
.value("PERCENT_A_OF_B", PERCENT_A_OF_B)
.value("EQUALS", EQUALS)
.value("NOT_EQUALS", NOT_EQUALS)
.value("GREATER_THAN", GREATER_THAN)
.value("LESS_THAN", LESS_THAN)
.value("UPPERCASE", UPPERCASE)
.value("LOWERCASE", LOWERCASE)
.value("LENGTH", LENGTH)
.value("IS", IS)
.value("CONCAT_SPACE", CONCAT_SPACE)
.value("CONCAT_COMMA", CONCAT_COMMA)
.value("BUCKET_10", BUCKET_10)
Expand Down
5 changes: 5 additions & 0 deletions cpp/perspective/src/include/perspective/computed.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@ enum t_computed_function_name {
SQRT,
ABS,
PERCENT_A_OF_B,
EQUALS,
NOT_EQUALS,
GREATER_THAN,
LESS_THAN,
UPPERCASE,
LOWERCASE,
LENGTH,
IS,
CONCAT_SPACE,
CONCAT_COMMA,
BUCKET_10,
Expand Down
18 changes: 17 additions & 1 deletion cpp/perspective/src/include/perspective/computed_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ t_tscalar divide(t_tscalar x, t_tscalar y);
template <t_dtype T>
t_tscalar percent_of(t_tscalar x, t_tscalar y);

template <t_dtype T>
t_tscalar equals(t_tscalar x, t_tscalar y);

template <t_dtype T>
t_tscalar not_equals(t_tscalar x, t_tscalar y);

template <t_dtype T>
t_tscalar greater_than(t_tscalar x, t_tscalar y);

template <t_dtype T>
t_tscalar less_than(t_tscalar x, t_tscalar y);

#define NUMERIC_FUNCTION_2_HEADER(NAME) \
template <> t_tscalar NAME<DTYPE_UINT8>(t_tscalar x, t_tscalar y); \
template <> t_tscalar NAME<DTYPE_UINT16>(t_tscalar x, t_tscalar y); \
Expand All @@ -89,10 +101,14 @@ NUMERIC_FUNCTION_2_HEADER(add);
NUMERIC_FUNCTION_2_HEADER(subtract);
NUMERIC_FUNCTION_2_HEADER(multiply);
NUMERIC_FUNCTION_2_HEADER(divide);
NUMERIC_FUNCTION_2_HEADER(percent_of);
NUMERIC_FUNCTION_2_HEADER(equals);
NUMERIC_FUNCTION_2_HEADER(not_equals);
NUMERIC_FUNCTION_2_HEADER(greater_than);
NUMERIC_FUNCTION_2_HEADER(less_than);

// String functions
t_tscalar length(t_tscalar x);
t_tscalar is(t_tscalar x, t_tscalar y);

// Functions that return a string/write into a string column should not return,
// and instead write directly into the output column. This prevents pointers to
Expand Down
45 changes: 45 additions & 0 deletions packages/perspective-viewer/src/js/computed_column.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,42 @@ export const COMPUTATIONS = {
["Math"],
2
),
equals: new Computation(
"==",
(x, y) => `(${x} == ${y})`,
"float",
"float",
(a, b) => a === b,
["Math"],
2
),
not_equals: new Computation(
"!=",
(x, y) => `(${x} != ${y})`,
"float",
"boolean",
(a, b) => a !== b,
["Math"],
2
),
greater_than: new Computation(
">",
(x, y) => `(${x} > ${y})`,
"float",
"boolean",
(a, b) => a > b,
["Math"],
2
),
less_than: new Computation(
"<",
(x, y) => `(${x} < ${y})`,
"float",
"boolean",
(a, b) => a < b,
["Math"],
2
),
uppercase: new Computation(
"Uppercase",
x => `uppercase(${x})`,
Expand All @@ -253,6 +289,15 @@ export const COMPUTATIONS = {
x => x.length,
["Text"]
),
is: new Computation(
"is",
(x, y) => `(${x} is ${y})`,
"string",
"boolean",
(x, y) => x === y,
["Text"],
2
),
concat_space: new Computation(
"concat_space",
x => `concat_space(${x})`,
Expand Down
10 changes: 10 additions & 0 deletions packages/perspective/src/js/perspective.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,22 @@ export default function(Module) {
return __MODULE__.t_computed_function_name.ABS;
case "%":
return __MODULE__.t_computed_function_name.PERCENT_A_OF_B;
case "==":
return __MODULE__.t_computed_function_name.EQUALS;
case "!=":
return __MODULE__.t_computed_function_name.NOT_EQUALS;
case ">":
return __MODULE__.t_computed_function_name.GREATER_THAN;
case "<":
return __MODULE__.t_computed_function_name.LESS_THAN;
case "Uppercase":
return __MODULE__.t_computed_function_name.UPPERCASE;
case "Lowercase":
return __MODULE__.t_computed_function_name.LOWERCASE;
case "length":
return __MODULE__.t_computed_function_name.LENGTH;
case "is":
return __MODULE__.t_computed_function_name.IS;
case "concat_space":
return __MODULE__.t_computed_function_name.CONCAT_SPACE;
case "concat_comma":
Expand Down
Loading