expressions.hpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2020-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #pragma once
6 
9 #include <cudf/scalar/scalar.hpp>
12 #include <cudf/types.hpp>
13 #include <cudf/utilities/error.hpp>
14 
15 #include <cstdint>
16 #include <functional>
17 #include <initializer_list>
18 #include <memory>
19 #include <optional>
20 #include <vector>
21 
27 namespace CUDF_EXPORT cudf {
28 
29 namespace detail {
30 namespace row_ir {
31 
41 struct node;
42 
46 struct ast_converter;
47 
48 } // namespace row_ir
49 } // namespace detail
50 
51 namespace ast {
57 // Forward declaration.
58 namespace detail {
59 class expression_parser;
60 class expression_transformer;
61 } // namespace detail
62 
69 struct [[nodiscard]] expression {
76  virtual cudf::size_type accept(detail::expression_parser& visitor) const = 0;
77 
84  virtual std::reference_wrapper<expression const> accept(
85  detail::expression_transformer& visitor) const = 0;
86 
93  [[nodiscard]] virtual std::unique_ptr<cudf::detail::row_ir::node> accept(
94  cudf::detail::row_ir::ast_converter& visitor) const = 0;
95 
103  [[nodiscard]] bool may_evaluate_null(table_view const& left, rmm::cuda_stream_view stream) const
104  {
105  return may_evaluate_null(left, left, stream);
106  }
107 
116  [[nodiscard]] virtual bool may_evaluate_null(table_view const& left,
117  table_view const& right,
118  rmm::cuda_stream_view stream) const = 0;
119 
120  virtual ~expression() {}
121 };
122 
128 enum class table_reference {
129  LEFT,
130  RIGHT,
131  OUTPUT
132 };
133 
138  public:
145  template <typename T>
146  __device__ T const value() const noexcept
147  {
148  if constexpr (std::is_same_v<T, cudf::string_view>) {
149  return string_view(static_cast<char const*>(_data), _size);
150  }
151  if constexpr (cudf::is_fixed_point<T>()) {
152  using rep_type = typename T::rep;
153  auto const rep = *static_cast<rep_type const*>(_data);
154  auto const scale = numeric::scale_type{type().scale()};
155  return T{numeric::scaled_integer<rep_type>{rep, scale}};
156  }
157  return *static_cast<T const*>(_data);
158  }
159 
164  template <typename T>
166  : generic_scalar_device_view(s.type(), s.data(), s.validity_data())
167  {
168  }
169 
174  template <typename T>
176  : generic_scalar_device_view(s.type(), s.data(), s.validity_data())
177  {
178  }
179 
184  template <typename T>
186  : generic_scalar_device_view(s.type(), s.data(), s.validity_data())
187  {
188  }
189 
195  : generic_scalar_device_view(s.type(), s.data(), s.validity_data(), s.size())
196  {
197  }
198 
203  template <typename T>
205  : generic_scalar_device_view{s.type(), s.data(), s.validity_data()}
206  {
207  }
208 
209  protected:
210  void const* _data{};
211  size_type const _size{};
212 
221  generic_scalar_device_view(data_type type, void const* data, bool* is_valid)
222  : cudf::detail::scalar_device_view_base(type, is_valid), _data(data)
223  {
224  }
225 
234  generic_scalar_device_view(data_type type, void const* data, bool* is_valid, size_type size)
235  : cudf::detail::scalar_device_view_base(type, is_valid), _data(data), _size(size)
236  {
237  }
238 };
239 
243 class literal : public expression {
244  public:
251  template <typename T>
252  literal(cudf::numeric_scalar<T>& value) : scalar(value), value(value)
253  {
254  }
255 
262  template <typename T>
263  literal(cudf::timestamp_scalar<T>& value) : scalar(value), value(value)
264  {
265  }
266 
273  template <typename T>
274  literal(cudf::duration_scalar<T>& value) : scalar(value), value(value)
275  {
276  }
277 
283  literal(cudf::string_scalar& value) : scalar(value), value(value) {}
284 
290  template <typename T>
291  literal(cudf::fixed_point_scalar<T>& value) : scalar(value), value(value)
292  {
293  }
294 
300  [[nodiscard]] cudf::data_type get_data_type() const { return get_value().type(); }
301 
307  [[nodiscard]] generic_scalar_device_view get_value() const { return value; }
308 
314  [[nodiscard]] cudf::scalar const& get_scalar() const { return scalar; }
315 
319  cudf::size_type accept(detail::expression_parser& visitor) const override;
320 
324  std::reference_wrapper<expression const> accept(
325  detail::expression_transformer& visitor) const override;
326 
330  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
331  cudf::detail::row_ir::ast_converter& visitor) const override;
332 
333  [[nodiscard]] bool may_evaluate_null(table_view const& left,
334  table_view const& right,
335  rmm::cuda_stream_view stream) const override
336  {
337  return !is_valid(stream);
338  }
339 
346  [[nodiscard]] bool is_valid(rmm::cuda_stream_view stream) const
347  {
348  return scalar.is_valid(stream);
349  }
350 
351  private:
352  cudf::scalar const& scalar;
353  generic_scalar_device_view const value;
354 };
355 
359 class column_reference : public expression {
360  public:
369  table_reference table_source = table_reference::LEFT)
370  : column_index(column_index), table_source(table_source)
371  {
372  }
373 
379  [[nodiscard]] cudf::size_type get_column_index() const { return column_index; }
380 
386  [[nodiscard]] table_reference get_table_source() const { return table_source; }
387 
394  [[nodiscard]] cudf::data_type get_data_type(table_view const& table) const;
395 
403  [[nodiscard]] cudf::data_type get_data_type(table_view const& left_table,
404  table_view const& right_table) const;
405 
409  cudf::size_type accept(detail::expression_parser& visitor) const override;
410 
414  std::reference_wrapper<expression const> accept(
415  detail::expression_transformer& visitor) const override;
416 
417  [[nodiscard]] bool may_evaluate_null(table_view const& left,
418  table_view const& right,
419  rmm::cuda_stream_view stream) const override
420  {
421  return (table_source == table_reference::LEFT ? left : right).column(column_index).has_nulls();
422  }
423 
427  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
428  cudf::detail::row_ir::ast_converter& visitor) const override;
429 
430  private:
431  cudf::size_type column_index;
432  table_reference table_source;
433 };
434 
438 class operation : public expression {
439  public:
446  operation(ast_operator op, expression const& input);
447 
455  operation(ast_operator op, expression const& left, expression const& right);
456 
457  // operation only stores references to expressions, so it does not accept r-value
458  // references: the calling code must own the expressions.
459  operation(ast_operator op, expression&& input) = delete;
460  operation(ast_operator op, expression&& left, expression&& right) = delete;
461  operation(ast_operator op, expression&& left, expression const& right) = delete;
462  operation(ast_operator op, expression const& left, expression&& right) = delete;
463 
469  [[nodiscard]] ast_operator get_operator() const { return op; }
470 
476  [[nodiscard]] std::vector<std::reference_wrapper<expression const>> const& get_operands() const
477  {
478  return operands;
479  }
480 
484  cudf::size_type accept(detail::expression_parser& visitor) const override;
485 
489  std::reference_wrapper<expression const> accept(
490  detail::expression_transformer& visitor) const override;
491 
492  [[nodiscard]] bool may_evaluate_null(table_view const& left,
493  table_view const& right,
494  rmm::cuda_stream_view stream) const override;
495 
499  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
500  cudf::detail::row_ir::ast_converter& visitor) const override;
501 
502  private:
503  ast_operator op;
504  std::vector<std::reference_wrapper<expression const>> operands;
505 };
506 
507 namespace detail {
508 
513 class predicate : public expression {
514  public:
519  predicate(expression const& source) : source_{source} {}
520 
524  cudf::size_type accept(detail::expression_parser& visitor) const override;
525 
529  std::reference_wrapper<expression const> accept(
530  detail::expression_transformer& visitor) const override;
531 
532  [[nodiscard]] bool may_evaluate_null(table_view const& left,
533  table_view const& right,
534  rmm::cuda_stream_view stream) const override;
535 
539  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
540  cudf::detail::row_ir::ast_converter& visitor) const override;
541 
546  [[nodiscard]] expression const& get_operand() const { return source_; }
547 
548  private:
549  std::reference_wrapper<expression const> source_;
550 };
551 
552 } // namespace detail
553 
558  public:
565  column_name_reference(std::string column_name) : column_name(std::move(column_name)) {}
566 
572  [[nodiscard]] std::string get_column_name() const { return column_name; }
573 
577  cudf::size_type accept(detail::expression_parser& visitor) const override;
578 
582  std::reference_wrapper<expression const> accept(
583  detail::expression_transformer& visitor) const override;
584 
585  [[nodiscard]] bool may_evaluate_null(table_view const& left,
586  table_view const& right,
587  rmm::cuda_stream_view stream) const override
588  {
589  return true;
590  }
591 
595  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
596  cudf::detail::row_ir::ast_converter& visitor) const override;
597 
598  private:
599  std::string column_name;
600 };
601 
606 class tree {
607  public:
611  tree() = default;
612 
616  tree(tree&&) = default;
617 
622  tree& operator=(tree&&) = default;
623 
624  ~tree() = default;
625 
626  // the tree is not copyable
627  tree(tree const&) = delete;
628  tree& operator=(tree const&) = delete;
629 
635  template <typename Expr, typename... Args>
636  std::enable_if_t<std::is_base_of_v<expression, Expr>, Expr const&> emplace(Args&&... args)
637  {
638  auto expr = std::make_unique<Expr>(std::forward<Args>(args)...);
639  Expr const& expr_ref = *expr;
640  expressions.emplace_back(std::move(expr));
641  return expr_ref;
642  }
643 
649  template <typename Expr>
650  decltype(auto) push(Expr expr)
651  {
652  return emplace<Expr>(std::move(expr));
653  }
654 
659  [[nodiscard]] expression const& front() const { return *expressions.front(); }
660 
665  [[nodiscard]] expression const& back() const { return *expressions.back(); }
666 
671  [[nodiscard]] size_t size() const { return expressions.size(); }
672 
678  expression const& at(size_t index) { return *expressions.at(index); }
679 
685  expression const& operator[](size_t index) const { return *expressions[index]; }
686 
687  private:
688  // TODO: use better ownership semantics, the unique_ptr here is redundant. Consider using a bump
689  // allocator with type-erased deleters.
690  std::vector<std::unique_ptr<expression>> expressions;
691 };
692 
693 namespace jit {
694 
698 enum class op : uint8_t {
699  // Identity operators
700  IDENTITY,
701 
702  // Null handling operators
703  IS_NULL,
704 
705  COALESCE,
706  PREDICATE,
707 
709  ADD,
710  SUB,
711  MUL,
712  DIV,
713  NEG,
714  ABS,
715  MOD,
716  PYMOD,
717  TRUE_DIV,
718  FLOOR_DIV,
719 
721  ADD_OVERFLOW,
722  SUB_OVERFLOW,
723  MUL_OVERFLOW,
724  DIV_OVERFLOW,
725  NEG_OVERFLOW,
726  ABS_OVERFLOW,
727  MOD_OVERFLOW,
728  CHECK_PRECISION,
729 
731  BITWISE_AND,
732  BITWISE_INVERT,
733  BITWISE_OR,
734  BITWISE_XOR,
735  BITWISE_SHIFT_LEFT,
736  BITWISE_SHIFT_RIGHT,
737 
740  CAST_TO_INT8,
741  CAST_TO_INT16,
742  CAST_TO_INT32,
744  CAST_TO_UINT8,
745  CAST_TO_UINT16,
746  CAST_TO_UINT32,
748  CAST_TO_FLOAT32,
750  CAST_TO_DECIMAL32,
751  CAST_TO_DECIMAL64,
752  CAST_TO_DECIMAL128,
753  RESCALE,
754 
756  EQUAL,
757  NOT_EQUAL,
758  GREATER,
760  LESS,
761  LESS_EQUAL,
762  NULL_EQUAL,
765  LOGICAL_AND,
766  LOGICAL_OR,
767  LOGICAL_NOT,
768  IF_ELSE,
769 
771  CBRT,
772  CEIL,
773  FLOOR,
774  RINT,
775  SQRT,
776  POW,
777  EXP,
778  LOG,
779 
781  ARCCOS,
782  ARCCOSH,
783  ARCSIN,
784  ARCSINH,
785  ARCTAN,
786  ARCTANH,
787  COS,
788  COSH,
789  SIN,
790  SINH,
791  TAN,
792  TANH,
793 };
794 
806  op operator_id,
807  std::vector<std::reference_wrapper<expression const>> const& args,
809  std::optional<int32_t> target_scale = std::nullopt);
810 
822  op operator_id,
823  std::initializer_list<std::reference_wrapper<expression const>> args,
825  std::optional<int32_t> target_scale = std::nullopt);
826 
827 } // namespace jit
828  // end of group
830 } // namespace ast
831 } // namespace CUDF_EXPORT cudf
Enum defining the supported AST operators.
A expression referring to data from a column in a table.
cudf::size_type accept(detail::expression_parser &visitor) const override
Accepts a visitor class.
bool may_evaluate_null(table_view const &left, table_view const &right, rmm::cuda_stream_view stream) const override
Returns true if the expression may evaluate to null.
std::unique_ptr< cudf::detail::row_ir::node > accept(cudf::detail::row_ir::ast_converter &visitor) const override
Accepts a visitor class.
std::string get_column_name() const
Get the column name.
std::reference_wrapper< expression const > accept(detail::expression_transformer &visitor) const override
Accepts a visitor class.
column_name_reference(std::string column_name)
Construct a new column name reference object.
A expression referring to data from a column in a table.
bool may_evaluate_null(table_view const &left, table_view const &right, rmm::cuda_stream_view stream) const override
Returns true if the expression may evaluate to null.
cudf::data_type get_data_type(table_view const &left_table, table_view const &right_table) const
Get the data type.
std::unique_ptr< cudf::detail::row_ir::node > accept(cudf::detail::row_ir::ast_converter &visitor) const override
Accepts a visitor class.
cudf::size_type accept(detail::expression_parser &visitor) const override
Accepts a visitor class.
cudf::data_type get_data_type(table_view const &table) const
Get the data type.
std::reference_wrapper< expression const > accept(detail::expression_transformer &visitor) const override
Accepts a visitor class.
table_reference get_table_source() const
Get the table source.
column_reference(cudf::size_type column_index, table_reference table_source=table_reference::LEFT)
Construct a new column reference object.
cudf::size_type get_column_index() const
Get the column index.
An expression that represents a predicate.
std::reference_wrapper< expression const > accept(detail::expression_transformer &visitor) const override
Accepts a visitor class.
predicate(expression const &source)
Construct a new filter predicate object.
expression const & get_operand() const
Get the operand expression.
std::unique_ptr< cudf::detail::row_ir::node > accept(cudf::detail::row_ir::ast_converter &visitor) const override
Accepts a visitor class.
cudf::size_type accept(detail::expression_parser &visitor) const override
Accepts a visitor class.
bool may_evaluate_null(table_view const &left, table_view const &right, rmm::cuda_stream_view stream) const override
Returns true if the expression may evaluate to null.
A type-erased scalar_device_view where the value is a fixed width type or a string.
generic_scalar_device_view(duration_scalar< T > &s)
Construct a new generic scalar device view object from a duration scalar.
generic_scalar_device_view(cudf::fixed_point_scalar< T > &s)
Construct a new generic scalar device view object from a fixed-point scalar.
generic_scalar_device_view(data_type type, void const *data, bool *is_valid)
Construct a new fixed width scalar device view object.
generic_scalar_device_view(string_scalar &s)
Construct a new generic scalar device view object from a string scalar.
generic_scalar_device_view(timestamp_scalar< T > &s)
Construct a new generic scalar device view object from a timestamp scalar.
generic_scalar_device_view(data_type type, void const *data, bool *is_valid, size_type size)
Construct a new string scalar device view object.
T const value() const noexcept
Returns the stored value.
generic_scalar_device_view(numeric_scalar< T > &s)
Construct a new generic scalar device view object from a numeric scalar.
A literal value used in an abstract syntax tree.
literal(cudf::numeric_scalar< T > &value)
Construct a new literal object.
std::unique_ptr< cudf::detail::row_ir::node > accept(cudf::detail::row_ir::ast_converter &visitor) const override
Accepts a visitor class.
cudf::size_type accept(detail::expression_parser &visitor) const override
Accepts a visitor class.
generic_scalar_device_view get_value() const
Get the value object.
cudf::data_type get_data_type() const
Get the data type.
literal(cudf::string_scalar &value)
Construct a new literal object.
cudf::scalar const & get_scalar() const
Get the scalar.
literal(cudf::duration_scalar< T > &value)
Construct a new literal object.
bool is_valid(rmm::cuda_stream_view stream) const
Check if the underlying scalar is valid.
std::reference_wrapper< expression const > accept(detail::expression_transformer &visitor) const override
Accepts a visitor class.
bool may_evaluate_null(table_view const &left, table_view const &right, rmm::cuda_stream_view stream) const override
Returns true if the expression may evaluate to null.
literal(cudf::fixed_point_scalar< T > &value)
Construct a new literal object.
literal(cudf::timestamp_scalar< T > &value)
Construct a new literal object.
An operation expression holds an operator and zero or more operands.
std::unique_ptr< cudf::detail::row_ir::node > accept(cudf::detail::row_ir::ast_converter &visitor) const override
Accepts a visitor class.
bool may_evaluate_null(table_view const &left, table_view const &right, rmm::cuda_stream_view stream) const override
Returns true if the expression may evaluate to null.
std::vector< std::reference_wrapper< expression const > > const & get_operands() const
Get the operands.
ast_operator get_operator() const
Get the operator.
operation(ast_operator op, expression const &left, expression const &right)
Construct a new binary operation object.
std::reference_wrapper< expression const > accept(detail::expression_transformer &visitor) const override
Accepts a visitor class.
operation(ast_operator op, expression const &input)
Construct a new unary operation object.
cudf::size_type accept(detail::expression_parser &visitor) const override
Accepts a visitor class.
An AST expression tree. It owns and contains multiple dependent expressions. All the expressions are ...
tree(tree &&)=default
Moves the ast tree.
tree & operator=(tree &&)=default
move-assigns the AST tree
size_t size() const
get the number of expressions added to the tree
std::enable_if_t< std::is_base_of_v< expression, Expr >, Expr const & > emplace(Args &&... args)
Add an expression to the AST tree.
tree()=default
construct an empty ast tree
expression const & front() const
get the first expression in the tree
expression const & at(size_t index)
get the expression at an index in the tree. Index is checked.
expression const & back() const
get the last expression in the tree
expression const & operator[](size_t index) const
get the expression at an index in the tree. Index is unchecked.
Indicator for the logical data type of an element in a column.
Definition: types.hpp:286
A non-owning view of scalar from device that is trivially copyable and usable in CUDA device code.
An owning class to represent a duration value in device memory.
Definition: scalar.hpp:657
An owning class to represent a fixed_point number in device memory.
Definition: scalar.hpp:289
An owning class to represent a numerical value in device memory.
Definition: scalar.hpp:229
An owning class to represent a singular value.
Definition: scalar.hpp:41
bool is_valid(rmm::cuda_stream_view stream=cudf::get_default_stream()) const
Indicates whether the scalar contains a valid value.
An owning class to represent a string in device memory.
Definition: scalar.hpp:411
A non-owning, immutable view of device data that is a variable length char array representing a UTF-8...
Definition: string_view.hpp:35
A set of cudf::column_view's of the same size.
Definition: table_view.hpp:206
A set of cudf::column's of the same size.
Definition: table.hpp:31
An owning class to represent a timestamp value in device memory.
Definition: scalar.hpp:601
Exception types and error-checking macros used throughout libcudf.
op
JIT operation kinds for cudf::ast::jit::operation.
@ ADD_OVERFLOW
Overflow-checking Arithmetic functions. raise errors on overflow, division by zero,...
@ CAST_TO_BOOL8
Type conversion/scaling operators.
Class definition for fixed point data type.
table_reference
Enum of table references.
ast_operator
Enum of supported operators.
@ RIGHT
Column index in the right table.
@ OUTPUT
Column index in the output table.
@ LEFT
Column index in the left table.
@ TANH
Hyperbolic tangent.
@ DIV
operator / using common type of lhs and rhs
@ CBRT
Cube-root (x^(1.0/3))
@ ARCSINH
Hyperbolic sine inverse.
@ SQRT
Square-root (x^0.5)
@ PYMOD
operator % using Python's sign rules for negatives
@ LOG
Natural Logarithm (base e)
@ FLOOR
largest integer value not greater than arg
@ ARCTAN
Trigonometric tangent inverse.
@ SIN
Trigonometric sine.
@ CEIL
Smallest integer value not less than arg.
@ ARCSIN
Trigonometric sine inverse.
@ RINT
Rounds the floating-point argument arg to an integer value.
@ TAN
Trigonometric tangent.
@ ARCCOS
Trigonometric cosine inverse.
@ ABS
Absolute value.
@ ARCTANH
Hyperbolic tangent inverse.
@ GREATER_EQUAL
operator >=
@ EXP
Exponential (base e, Euler number)
@ CAST_TO_FLOAT64
Cast value to double.
@ TRUE_DIV
operator / after promoting type to floating point
@ LOGICAL_AND
operator &&
@ SINH
Hyperbolic sine.
@ CAST_TO_UINT64
Cast value to uint64_t.
@ COSH
Hyperbolic cosine.
@ ARCCOSH
Hyperbolic cosine inverse.
@ IDENTITY
Identity function.
@ IS_NULL
Check if operand is null.
@ CAST_TO_INT64
Cast value to int64_t.
@ COS
Trigonometric cosine.
scale_type
The scale type for fixed_point.
Definition: fixed_point.hpp:38
std::unique_ptr< cudf::column > is_valid(cudf::column_view const &input, rmm::cuda_stream_view stream=cudf::get_default_stream(), rmm::device_async_resource_ref mr=cudf::get_current_device_resource_ref())
Creates a column of type_id::BOOL8 elements where for every element in input true indicates the value...
int32_t size_type
Row index type for columns and tables.
Definition: types.hpp:84
error_policy
Indicates whether a function nullifies its output on error.
Definition: types.hpp:267
@ PROPAGATE
The function propagates errors.
cuDF interfaces
Definition: host_udf.hpp:26
Class definitions for cudf::scalar.
Scalar device view class definitions.
A generic expression that can be evaluated to return a value.
Definition: expressions.hpp:69
virtual std::unique_ptr< cudf::detail::row_ir::node > accept(cudf::detail::row_ir::ast_converter &visitor) const =0
Accepts an row_ir::ast_converter class.
bool may_evaluate_null(table_view const &left, rmm::cuda_stream_view stream) const
Returns true if the expression may evaluate to null.
virtual cudf::size_type accept(detail::expression_parser &visitor) const =0
Accepts a visitor class.
virtual std::reference_wrapper< expression const > accept(detail::expression_transformer &visitor) const =0
Accepts a visitor class.
virtual bool may_evaluate_null(table_view const &left, table_view const &right, rmm::cuda_stream_view stream) const =0
Returns true if the expression may evaluate to null.
Helper struct for constructing fixed_point when value is already shifted.
Class definitions for (mutable)_table_view
Type declarations for libcudf.