Skip to content

Report one-row Sequence arrays as sorted for any multiplier - #10602

Open
ump45nose wants to merge 3 commits into
vortex-data:developfrom
ump45nose:fix/singleton-sequence-sortedness
Open

ump45nose wants to merge 3 commits into
vortex-data:developfrom
ump45nose:fix/singleton-sequence-sortedness

Conversation

@ump45nose

Copy link
Copy Markdown

Summary

Closes #10579.

A one-row Sequence has no adjacent pair to compare, so it is sorted and strictly sorted whatever its multiplier. Its constructor stats, its is_sorted aggregate kernel and the generic sortedness helper answered from the multiplier (or a cached hint) alone, so a negative multiplier reported unsorted and a zero multiplier reported not strictly sorted.

Changes

  • Sequence::stats now takes the length and reports both flags as exact true when it is at most 1. This covers try_new, try_new_typed and slicing, which goes through new_unchecked.
  • SequenceIsSortedKernel returns true for a one-row batch, so direct aggregate execution agrees with the stats.
  • is_sorted_impl checks len() <= 1 before the cached statistics, so a stale hint can't contradict it.
  • SerializedArray::decode sets both flags to exact true for arrays with at most one element after it restores the stored statistics. Files written before this change can store the multiplier-only answer for one-row sequences, and this makes the intrinsic fact win over those historical hints.

New tests cover the typed and untyped constructors and a one-row slice of a longer sequence (multipliers -1, 0 and 3), the kernel called directly for strict and non-strict, decoding a one-row sequence whose serialized hints say unsorted, and the generic helper with stale cached stats. Apart from the positive-multiplier cases, they all fail on develop.

AI assistance

This PR was written by an AI coding agent working under my account (code, tests and this description), and I'm the responsible human for it. Points worth a reviewer's attention: the decode change in vortex-array/src/serde.rs applies to every encoding, not only Sequence, on the basis that any array with at most one element is (strictly) sorted; and it overwrites the stored hint with exact true rather than dropping it.

A Sequence with a single element has no adjacent pair to compare, so it is
sorted and strictly sorted whatever its multiplier. The constructor stats,
the Sequence is_sorted aggregate kernel and the generic sortedness helper
all answered from the multiplier (or a cached hint) alone, so a one-row
Sequence with a negative multiplier reported unsorted, and one with a zero
multiplier reported not strictly sorted.

Decoding also restores the stored sortedness hints, which older writers
computed the same way, so a decoded one-row array now takes the intrinsic
answer over those hints.

Closes vortex-data#10579

Signed-off-by: Vincent <1729065730@qq.com>
@codspeed

codspeed Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Merging this PR will regress 3 benchmarks

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚠️ 2 benchmarks measured no execution time

Nothing ran under measurement, usually because the compiler removed the code under test. These results are not comparable, so they count as unchanged.

Preventing compiler optimizations

⚠️ 19 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

ℹ️ 40 benchmarks have no flame graph

The flamegraph could not be generated because we failed to resolve the symbols in the profiling trace. This happens when we fail to harvest information about language frames.

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 5 improved benchmarks
❌ 3 regressed benchmarks
✅ 2400 untouched benchmarks
⏩ 12 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ ⚠️ Simulation isolated_runs[u32, (16, 0)] 78.3 µs 98.5 µs -20.45%
❌ WallTime threshold_neon[80] 3.4 µs 3.8 µs -10.5%
❌ WallTime starts_with_avx2[64, VarBin] 53.7 µs 60 µs -10.43%
⚡ WallTime bitpack_blocked_compress_avx512 5.6 µs 4.8 µs +17.52%
⚡ ℹ️ Simulation test_scan_filter_to_arrow_array[int_float] 4.1 ms 3.5 ms +15.59%
⚡ ℹ️ Simulation test_repeated_scan_filter[int_float] 3.9 ms 3.5 ms +12.09%
⚡ ℹ️ Simulation test_repeated_scan_filter[int] 2.8 ms 2.5 ms +11.62%
⚡ ℹ️ Simulation test_scan_filter_to_arrow_array[int] 2.8 ms 2.5 ms +10.99%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing ump45nose:fix/singleton-sequence-sortedness (de3e710) with develop (07fe4c5)

Open in CodSpeed

Footnotes

  1. 12 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@connortsui20
connortsui20 self-requested a review October 19, 2026 13:04
Comment on lines +38 to +52
// A single element is strictly sorted whatever the multiplier.
let result = if array.len() <= 1 {
true
} else {
let m = array.multiplier();
match_each_native_ptype!(m.ptype(), |P| {
m.cast::<P>().map(|x| {
if options.strict {
x > zero::<P>()
} else {
x >= zero::<P>()
}
})
})?
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why check twice???

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two checks cover different paths. is_sorted returns early for len <= 1, but the accumulator hands this kernel each chunk of a ChunkedArray directly, and IsSorted has no legacy stat bridge, so neither that early return nor the constructor stats are consulted there. Without the kernel check, a one-row Sequence chunk with a negative multiplier makes an otherwise sorted chunked array report unsorted. In de3e710 I added a comment in the kernel and singleton_chunk_keeps_chunked_array_sorted, which fails without the check. (AI-assisted reply.)

The Sequence is_sorted kernel keeps its own len <= 1 check even though
is_sorted already returns early for such arrays: the accumulator hands the
kernel each chunk of a ChunkedArray directly, so the outer check never
runs for a one-row chunk. Explain this in the kernel and cover it with a
chunked-array test that fails without the check.

Signed-off-by: Vincent <1729065730@qq.com>

@connortsui20 connortsui20 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to consolidate the logic into one function like:

fn is_sorted(multiplier: PValue, length: usize, strict: bool) -> bool

Move the length and multiplier logic into Sequence::is_sorted(multiplier,
length, strict) and use it for the constructor stats and the is_sorted
kernel.

Signed-off-by: Vincent <1729065730@qq.com>
@ump45nose

Copy link
Copy Markdown
Author

Done in d58de2d. Sequence::is_sorted(multiplier, length, strict) now holds the length and multiplier logic, and both the constructor stats and the kernel call it. (AI-assisted reply.)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Singleton Sequence arrays report incorrect sortedness

3 participants