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 
22 namespace CUDF_EXPORT cudf {
23 
24 namespace detail {
25 namespace row_ir {
26 
36 struct node;
37 
41 struct ast_converter;
42 
43 } // namespace row_ir
44 } // namespace detail
45 
46 namespace ast {
54 // Forward declaration.
55 namespace detail {
56 class expression_parser;
57 class expression_transformer;
58 } // namespace detail
59 
66 struct [[nodiscard]] expression {
73  virtual cudf::size_type accept(detail::expression_parser& visitor) const = 0;
74 
81  virtual std::reference_wrapper<expression const> accept(
82  detail::expression_transformer& visitor) const = 0;
83 
90  [[nodiscard]] virtual std::unique_ptr<cudf::detail::row_ir::node> accept(
91  cudf::detail::row_ir::ast_converter& visitor) const = 0;
92 
100  [[nodiscard]] bool may_evaluate_null(table_view const& left, rmm::cuda_stream_view stream) const
101  {
102  return may_evaluate_null(left, left, stream);
103  }
104 
113  [[nodiscard]] virtual bool may_evaluate_null(table_view const& left,
114  table_view const& right,
115  rmm::cuda_stream_view stream) const = 0;
116 
117  virtual ~expression() {}
118 };
119 
125 enum class table_reference {
126  LEFT,
127  RIGHT,
128  OUTPUT
129 };
130 
135  public:
142  template <typename T>
143  __device__ T const value() const noexcept
144  {
145  if constexpr (std::is_same_v<T, cudf::string_view>) {
146  return string_view(static_cast<char const*>(_data), _size);
147  }
148  if constexpr (cudf::is_fixed_point<T>()) {
149  using rep_type = typename T::rep;
150  auto const rep = *static_cast<rep_type const*>(_data);
151  auto const scale = numeric::scale_type{type().scale()};
152  return T{numeric::scaled_integer<rep_type>{rep, scale}};
153  }
154  return *static_cast<T const*>(_data);
155  }
156 
161  template <typename T>
163  : generic_scalar_device_view(s.type(), s.data(), s.validity_data())
164  {
165  }
166 
171  template <typename T>
173  : generic_scalar_device_view(s.type(), s.data(), s.validity_data())
174  {
175  }
176 
181  template <typename T>
183  : generic_scalar_device_view(s.type(), s.data(), s.validity_data())
184  {
185  }
186 
192  : generic_scalar_device_view(s.type(), s.data(), s.validity_data(), s.size())
193  {
194  }
195 
200  template <typename T>
202  : generic_scalar_device_view{s.type(), s.data(), s.validity_data()}
203  {
204  }
205 
206  protected:
207  void const* _data{};
208  size_type const _size{};
209 
218  generic_scalar_device_view(data_type type, void const* data, bool* is_valid)
219  : cudf::detail::scalar_device_view_base(type, is_valid), _data(data)
220  {
221  }
222 
231  generic_scalar_device_view(data_type type, void const* data, bool* is_valid, size_type size)
232  : cudf::detail::scalar_device_view_base(type, is_valid), _data(data), _size(size)
233  {
234  }
235 };
236 
240 class literal : public expression {
241  public:
248  template <typename T>
249  literal(cudf::numeric_scalar<T>& value) : scalar(value), value(value)
250  {
251  }
252 
259  template <typename T>
260  literal(cudf::timestamp_scalar<T>& value) : scalar(value), value(value)
261  {
262  }
263 
270  template <typename T>
271  literal(cudf::duration_scalar<T>& value) : scalar(value), value(value)
272  {
273  }
274 
280  literal(cudf::string_scalar& value) : scalar(value), value(value) {}
281 
287  template <typename T>
288  literal(cudf::fixed_point_scalar<T>& value) : scalar(value), value(value)
289  {
290  }
291 
297  [[nodiscard]] cudf::data_type get_data_type() const { return get_value().type(); }
298 
304  [[nodiscard]] generic_scalar_device_view get_value() const { return value; }
305 
311  [[nodiscard]] cudf::scalar const& get_scalar() const { return scalar; }
312 
316  cudf::size_type accept(detail::expression_parser& visitor) const override;
317 
321  std::reference_wrapper<expression const> accept(
322  detail::expression_transformer& visitor) const override;
323 
327  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
328  cudf::detail::row_ir::ast_converter& visitor) const override;
329 
330  [[nodiscard]] bool may_evaluate_null(table_view const& left,
331  table_view const& right,
332  rmm::cuda_stream_view stream) const override
333  {
334  return !is_valid(stream);
335  }
336 
343  [[nodiscard]] bool is_valid(rmm::cuda_stream_view stream) const
344  {
345  return scalar.is_valid(stream);
346  }
347 
348  private:
349  cudf::scalar const& scalar;
350  generic_scalar_device_view const value;
351 };
352 
356 class column_reference : public expression {
357  public:
366  table_reference table_source = table_reference::LEFT)
367  : column_index(column_index), table_source(table_source)
368  {
369  }
370 
376  [[nodiscard]] cudf::size_type get_column_index() const { return column_index; }
377 
383  [[nodiscard]] table_reference get_table_source() const { return table_source; }
384 
391  [[nodiscard]] cudf::data_type get_data_type(table_view const& table) const;
392 
400  [[nodiscard]] cudf::data_type get_data_type(table_view const& left_table,
401  table_view const& right_table) const;
402 
406  cudf::size_type accept(detail::expression_parser& visitor) const override;
407 
411  std::reference_wrapper<expression const> accept(
412  detail::expression_transformer& visitor) const override;
413 
414  [[nodiscard]] bool may_evaluate_null(table_view const& left,
415  table_view const& right,
416  rmm::cuda_stream_view stream) const override
417  {
418  return (table_source == table_reference::LEFT ? left : right).column(column_index).has_nulls();
419  }
420 
424  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
425  cudf::detail::row_ir::ast_converter& visitor) const override;
426 
427  private:
428  cudf::size_type column_index;
429  table_reference table_source;
430 };
431 
435 class operation : public expression {
436  public:
443  operation(ast_operator op, expression const& input);
444 
452  operation(ast_operator op, expression const& left, expression const& right);
453 
454  // operation only stores references to expressions, so it does not accept r-value
455  // references: the calling code must own the expressions.
456  operation(ast_operator op, expression&& input) = delete;
457  operation(ast_operator op, expression&& left, expression&& right) = delete;
458  operation(ast_operator op, expression&& left, expression const& right) = delete;
459  operation(ast_operator op, expression const& left, expression&& right) = delete;
460 
466  [[nodiscard]] ast_operator get_operator() const { return op; }
467 
473  [[nodiscard]] std::vector<std::reference_wrapper<expression const>> const& get_operands() const
474  {
475  return operands;
476  }
477 
481  cudf::size_type accept(detail::expression_parser& visitor) const override;
482 
486  std::reference_wrapper<expression const> accept(
487  detail::expression_transformer& visitor) const override;
488 
489  [[nodiscard]] bool may_evaluate_null(table_view const& left,
490  table_view const& right,
491  rmm::cuda_stream_view stream) const override;
492 
496  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
497  cudf::detail::row_ir::ast_converter& visitor) const override;
498 
499  private:
500  ast_operator op;
501  std::vector<std::reference_wrapper<expression const>> operands;
502 };
503 
504 namespace detail {
505 
510 class predicate : public expression {
511  public:
516  predicate(expression const& source) : source_{source} {}
517 
521  cudf::size_type accept(detail::expression_parser& visitor) const override;
522 
526  std::reference_wrapper<expression const> accept(
527  detail::expression_transformer& visitor) const override;
528 
529  [[nodiscard]] bool may_evaluate_null(table_view const& left,
530  table_view const& right,
531  rmm::cuda_stream_view stream) const override;
532 
536  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
537  cudf::detail::row_ir::ast_converter& visitor) const override;
538 
543  [[nodiscard]] expression const& get_operand() const { return source_; }
544 
545  private:
546  std::reference_wrapper<expression const> source_;
547 };
548 
549 } // namespace detail
550 
555  public:
562  column_name_reference(std::string column_name) : column_name(std::move(column_name)) {}
563 
569  [[nodiscard]] std::string get_column_name() const { return column_name; }
570 
574  cudf::size_type accept(detail::expression_parser& visitor) const override;
575 
579  std::reference_wrapper<expression const> accept(
580  detail::expression_transformer& visitor) const override;
581 
582  [[nodiscard]] bool may_evaluate_null(table_view const& left,
583  table_view const& right,
584  rmm::cuda_stream_view stream) const override
585  {
586  return true;
587  }
588 
592  [[nodiscard]] std::unique_ptr<cudf::detail::row_ir::node> accept(
593  cudf::detail::row_ir::ast_converter& visitor) const override;
594 
595  private:
596  std::string column_name;
597 };
598 
603 class tree {
604  public:
608  tree() = default;
609 
613  tree(tree&&) = default;
614 
619  tree& operator=(tree&&) = default;
620 
621  ~tree() = default;
622 
623  // the tree is not copyable
624  tree(tree const&) = delete;
625  tree& operator=(tree const&) = delete;
626 
632  template <typename Expr, typename... Args>
633  std::enable_if_t<std::is_base_of_v<expression, Expr>, Expr const&> emplace(Args&&... args)
634  {
635  auto expr = std::make_unique<Expr>(std::forward<Args>(args)...);
636  Expr const& expr_ref = *expr;
637  expressions.emplace_back(std::move(expr));
638  return expr_ref;
639  }
640 
646  template <typename Expr>
647  decltype(auto) push(Expr expr)
648  {
649  return emplace<Expr>(std::move(expr));
650  }
651 
656  [[nodiscard]] expression const& front() const { return *expressions.front(); }
657 
662  [[nodiscard]] expression const& back() const { return *expressions.back(); }
663 
668  [[nodiscard]] size_t size() const { return expressions.size(); }
669 
675  expression const& at(size_t index) { return *expressions.at(index); }
676 
682  expression const& operator[](size_t index) const { return *expressions[index]; }
683 
684  private:
685  // TODO: use better ownership semantics, the unique_ptr here is redundant. Consider using a bump
686  // allocator with type-erased deleters.
687  std::vector<std::unique_ptr<expression>> expressions;
688 };
689 
690 namespace jit {
691 
695 enum class op : uint8_t {
696  // Identity operators
697  IDENTITY,
698 
699  // Null handling operators
700  IS_NULL,
701 
702  COALESCE,
703  PREDICATE,
704 
706  ADD,
707  SUB,
708  MUL,
709  DIV,
710  NEG,
711  ABS,
712  MOD,
713  PYMOD,
714  TRUE_DIV,
715  FLOOR_DIV,
716 
718  ADD_OVERFLOW,
719  SUB_OVERFLOW,
720  MUL_OVERFLOW,
721  DIV_OVERFLOW,
722  NEG_OVERFLOW,
723  ABS_OVERFLOW,
724  MOD_OVERFLOW,
725  CHECK_PRECISION,
726 
728  BITWISE_AND,
729  BITWISE_INVERT,
730  BITWISE_OR,
731  BITWISE_XOR,
732  BITWISE_SHIFT_LEFT,
733  BITWISE_SHIFT_RIGHT,
734 
737  CAST_TO_INT8,
738  CAST_TO_INT16,
739  CAST_TO_INT32,
741  CAST_TO_UINT8,
742  CAST_TO_UINT16,
743  CAST_TO_UINT32,
745  CAST_TO_FLOAT32,
747  CAST_TO_DECIMAL32,
748  CAST_TO_DECIMAL64,
749  CAST_TO_DECIMAL128,
750  RESCALE,
751 
753  EQUAL,
754  NOT_EQUAL,
755  GREATER,
757  LESS,
758  LESS_EQUAL,
759  NULL_EQUAL,
762  LOGICAL_AND,
763  LOGICAL_OR,
764  LOGICAL_NOT,
765  IF_ELSE,
766 
768  CBRT,
769  CEIL,
770  FLOOR,
771  RINT,
772  SQRT,
773  POW,
774  EXP,
775  LOG,
776 
778  ARCCOS,
779  ARCCOSH,
780  ARCSIN,
781  ARCSINH,
782  ARCTAN,
783  ARCTANH,
784  COS,
785  COSH,
786  SIN,
787  SINH,
788  TAN,
789  TANH,
790 };
791 
803  op operator_id,
804  std::vector<std::reference_wrapper<expression const>> const& args,
806  std::optional<int32_t> target_scale = std::nullopt);
807 
819  op operator_id,
820  std::initializer_list<std::reference_wrapper<expression const>> args,
822  std::optional<int32_t> target_scale = std::nullopt);
823 
824 } // namespace jit
825  // end of group
827 } // namespace ast
828 } // 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:287
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:35
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:85
error_policy
Indicates whether a function nullifies its output on error.
Definition: types.hpp:268
@ 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:66
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.