Skip to content

Commit

Permalink
Fexpr ifelse (#2570)
Browse files Browse the repository at this point in the history
Converted `ifelse()` function into the new `FExpr` format.

WIP for #2562
  • Loading branch information
st-pasha authored Aug 14, 2020
1 parent a7816ca commit 373f856
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 46 deletions.
4 changes: 4 additions & 0 deletions src/core/expr/fexpr_func.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ Kind FExpr_Func::get_expr_kind() const {
return Kind::Func;
}

int FExpr_Func::precedence() const noexcept {
return 16;
}


// Forbid expressions like `f[f.A]`.
Workframe FExpr_Func::evaluate_f(EvalContext&, size_t) const {
Expand Down
7 changes: 3 additions & 4 deletions src/core/expr/fexpr_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,22 @@ namespace expr {
* at least the following:
*
* Workframe evaluate_n(EvalContext&) const;
* int precedence() const noexcept;
* std::string repr() const;
*
*/
class FExpr_Func : public FExpr {
public:
Kind get_expr_kind() const override;

// Workframe evaluate_n(EvalContext&) const = 0;
Workframe evaluate_f(EvalContext&, size_t) const override;
Workframe evaluate_j(EvalContext&) const override;
Workframe evaluate_r(EvalContext&, const sztvec&) const override;
RowIndex evaluate_i(EvalContext&) const override;
RiGb evaluate_iby(EvalContext&) const override;
int precedence() const noexcept override;

// int precedence() const noexcept = 0;
// std::string repr() const = 0;
// Workframe evaluate_n(EvalContext&) const override;
// std::string repr() const override;
};


Expand Down
76 changes: 47 additions & 29 deletions src/core/expr/head_func_ifelse.cc → src/core/expr/fexpr_ifelse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,43 @@
//------------------------------------------------------------------------------
#include "column/ifelse.h" // IfElse_ColumnImpl
#include "expr/eval_context.h" // EvalContext
#include "expr/expr.h" // Expr
#include "expr/head_func.h" // Head_Func_IfElse
#include "expr/fexpr_func.h" // FExpr_Func
#include "expr/workframe.h" // Workframe
#include "datatablemodule.h" // DatatableModule
#include "stype.h" // SType
namespace dt {
namespace expr {



//------------------------------------------------------------------------------
// Head_Func_IfElse
// FExpr_IfElse
//------------------------------------------------------------------------------
namespace dt {
namespace expr {

class FExpr_IfElse : public FExpr_Func {
private:
ptrExpr cond_;
ptrExpr true_;
ptrExpr false_;

public:
FExpr_IfElse(py::robj, py::robj, py::robj);
Workframe evaluate_n(EvalContext&) const override;
std::string repr() const override;
};


Workframe Head_Func_IfElse::evaluate_n(
const vecExpr& args, EvalContext& ctx) const
{
xassert(args.size() == 3);
Workframe wf_cond = args[0]->evaluate_n(ctx);
Workframe wf_true = args[1]->evaluate_n(ctx);
Workframe wf_false = args[2]->evaluate_n(ctx);

FExpr_IfElse::FExpr_IfElse(py::robj c, py::robj t, py::robj f)
: cond_(as_fexpr(c)),
true_(as_fexpr(t)),
false_(as_fexpr(f)) {}


Workframe FExpr_IfElse::evaluate_n(EvalContext& ctx) const {
Workframe wf_cond = cond_->evaluate_n(ctx);
Workframe wf_true = true_->evaluate_n(ctx);
Workframe wf_false = false_->evaluate_n(ctx);
if (wf_cond.ncols() != 1 || wf_true.ncols() != 1 || wf_false.ncols() != 1) {
throw TypeError() << "Multi-column expressions are not supported in "
"`ifelse()` function";
Expand Down Expand Up @@ -75,14 +90,20 @@ Workframe Head_Func_IfElse::evaluate_n(
}



ptrHead Head_Func_IfElse::make(Op, const py::otuple& params) {
xassert(params.size() == 0); (void) params;
return ptrHead(new Head_Func_IfElse());
std::string FExpr_IfElse::repr() const {
std::string out = "ifelse(";
out += cond_->repr();
out += ", ";
out += true_->repr();
out += ", ";
out += false_->repr();
out += ')';
return out;
}




}} // dt::expr


Expand All @@ -106,19 +127,19 @@ This may be relevant for those cases
Parameters
----------
condition: Expr
condition: FExpr
An expression yielding a single boolean column.
expr_if_true: Expr
expr_if_true: FExpr
Values that will be used when the condition evaluates to True.
This must be a single column (or equivalent).
This must be a single column.
expr_if_false: Expr
expr_if_false: FExpr
Values that will be used when the condition evaluates to False.
This must be a single column (or equivalent).
This must be a single column.
(return): Expr
The produced expression, is a single column whose stype is the
return: FExpr
The resulting expression is a single column whose stype is the
stype which is common for `expr_if_true` and `expr_if_false`,
i.e. it is the smallest stype into which both exprs can be
upcasted.
Expand All @@ -129,18 +150,15 @@ static PKArgs args_ifelse(
{"condition", "expr_if_true", "expr_if_false"},
"ifelse", doc_ifelse);

static oobj ifelse(const PKArgs& args)
{
static oobj ifelse(const PKArgs& args) {
robj arg_cond = args[0].to_robj();
robj arg_true = args[1].to_robj();
robj arg_false = args[2].to_robj();
if (!arg_cond || !arg_true || !arg_false) {
throw TypeError() << "Function `ifelse()` requires 3 arguments";
}
return robj(Expr_Type).call({
oint(static_cast<size_t>(dt::expr::Op::IFELSE)),
otuple({arg_cond, arg_true, arg_false})
});
return FExpr::make(
new dt::expr::FExpr_IfElse(arg_cond, arg_true, arg_false));
}


Expand Down
1 change: 0 additions & 1 deletion src/core/expr/head_func.cc
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ void Head_Func::init() {
factory[static_cast<size_t>(Op::SETPLUS)] = make_colsetop;
factory[static_cast<size_t>(Op::SETMINUS)] = make_colsetop;
factory[static_cast<size_t>(Op::SHIFTFN)] = &Head_Func_Shift::make;
factory[static_cast<size_t>(Op::IFELSE)] = &Head_Func_IfElse::make;
factory[static_cast<size_t>(Op::CUT)] = &Head_Func_Cut::make;
factory[static_cast<size_t>(Op::QCUT)] = &Head_Func_Qcut::make;
factory[static_cast<size_t>(Op::COUNT0)] = make_reduce0;
Expand Down
10 changes: 0 additions & 10 deletions src/core/expr/head_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,6 @@ class Head_Func_IsClose : public Head_Func {



class Head_Func_IfElse : public Head_Func {
public:
Head_Func_IfElse() = default;
static ptrHead make(Op, const py::otuple& params);

Workframe evaluate_n(const vecExpr&, EvalContext&) const override;
};



class Head_Func_Cut : public Head_Func {
private:
py::oobj py_nbins_;
Expand Down
1 change: 0 additions & 1 deletion src/core/expr/op.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ enum class Op : size_t {
SETPLUS = 3,
SETMINUS = 4,
SHIFTFN = 5, // head_func_shift.cc
IFELSE = 6,
CUT = 7,
QCUT = 8,

Expand Down
1 change: 0 additions & 1 deletion src/datatable/expr/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class OpCodes(enum.Enum):
SETPLUS = 3
SETMINUS = 4
SHIFTFN = 5
IFELSE = 6
CUT = 7
QCUT = 8

Expand Down

0 comments on commit 373f856

Please sign in to comment.