Skip to content

[FEA] Preserve Polars Array dtype in cudf-polars pass-through plans #23421

Description

@0guban0v

Is your feature request related to a problem? Please describe.

cudf_polars rejects pl.Array during schema conversion. This causes whole query to fall back to CPU even when no Array operation is requested and column only passes through otherwise supported GPU operations. This prevents GPU filtering or projection of scalar metadata while retaining fixed-size embedding columns.

Describe the solution you'd like

Support lossless pass-through for one-dimensional, all-valid pl.Array columns with fixed-width scalar dtypes already supported by libcudf.

Initial scope:

  • in-memory DataFrame scan
  • projection
  • filtering on another scalar column
  • slice
  • exact values, row order, dtype, and width
  • CPU fallback for unsupported Array cases

No Array arithmetic or reduction is needed.

Before implementing this, I'd like guidance from cudf_polars maintainers on representation boundary:
Should first implementation adapt Arrow fixed-size-list to regular libcudf LIST at cudf_polars ingress, retain original pl.Array shape in existing DataType, and reconstruct fixed-size-list output? Or should fixed-size-list support first be added to libcudf Arrow interoperability?

Describe alternatives you've considered

Users can manually convert Array to List before GPU execution and cast result back afterward. This loses fixed-width schema contract during execution and requires application-level conversion.

Current CPU fallback preserves correctness but prevents otherwise supported scalar filtering and projection from using GPU.

Adding native fixed-size-list support to libcudf Arrow interoperability would provide broader support, but may be larger than pass-through-only cudf_polars adapter.

Additional context

import polars as pl
from polars.testing import assert_frame_equal

df = pl.DataFrame(
    {
        "keep": [True, False, True],
        "embedding": pl.Series(
            [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]],
            dtype=pl.Array(pl.Float32, 2),
        ),
    }
)

query = df.lazy().filter("keep").select("embedding")

expected = query.collect()
result = query.collect(
    engine=pl.GPUEngine(
        executor="in-memory",
        raise_on_fail=True,
    )
)

assert_frame_equal(result, expected)
assert result.schema == expected.schema

Nullable or nested arrays, Array expressions such as arr.dot, file scans, and distributed execution are separate follow-up work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    cudf-polarsIssues specific to cudf-polarsfeature requestNew feature or request

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions