Skip to content

Fixed window temporal sampling - #5625

Open
ChuckHastings wants to merge 9 commits into
rapidsai:mainfrom
ChuckHastings:fixed_window_temporal_sampling
Open

Fixed window temporal sampling#5625
ChuckHastings wants to merge 9 commits into
rapidsai:mainfrom
ChuckHastings:fixed_window_temporal_sampling

Conversation

@ChuckHastings

Copy link
Copy Markdown
Collaborator

Add fixed window temporal sampling implementation, closes #5593

Also lays the groundwork for implementing last-n sampling, updating the API framework temporal sampling to make the last-n choice orthogonal to the temporal parameters.

@copy-pr-bot

copy-pr-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@ChuckHastings ChuckHastings self-assigned this Aug 12, 2026
@ChuckHastings ChuckHastings added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels Aug 12, 2026
@ChuckHastings
ChuckHastings marked this pull request as ready for review August 12, 2026 17:42
@ChuckHastings
ChuckHastings requested review from a team as code owners August 12, 2026 17:42

@seunghwak seunghwak left a comment

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.

Quick reviews/questions about the API changes.

More reviews on the implementation part are in progress.

time) */
LAST /** Support last n behavior */
FIXED_WINDOW, /** Apply the original per-seed time window at every hop */
LAST = FIXED_WINDOW /** Deprecated alias for FIXED_WINDOW */

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.

What is this? Last-N is not a temporal sampling method, it is a neighbor selection method (as specified in neighbor_selection_t), right? Should we better delete this to avoid confusion?

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.

Or last-N or first-N are based on time stamps, not priorities (biases)?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Last-N for the current use case is based on timestamps, but we already use timestamps to create biases, so we can easily implement with your new primitive. I think having it based on biases is a more flexible design anyway.

The LAST enum value was already defined, leaving this in place as deprecated to allow this to be a non-breaking API change. If a user previously called with LAST it would be valid, although it would have fast-failed as not implemented.

I'll change this so that it is not the same as FIXED_WINDOW (that's probably not correct) and instead returns a not implemented but deprecated error message. We'll actually delete the value in the next release.

enum class neighbor_selection_t {
RANDOM = 0, /** Random selection. Uniform if no bias view is supplied, biased otherwise. */
FIRST, /** Deterministically select the earliest edges. Not yet implemented. */
LAST /** Deterministically select the latest edges. Not yet implemented. */

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.

Similar here, last-N or first-N are based on time stamps?

In this case, does it make sense to set neighbor_selection_t to LAST and temporal_sampling_comparison_t to STRICTLY_INCREASING?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, that might be a cleaner design. I'll look at that.

Comment on lines +970 to +972
neighbor_selection_t neighbor_selection,
std::optional<temporal_sampling_comparison_t> temporal_sampling_comparison,
sampling_flags_t sampling_flags,

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.

Now we have neighbor_selection_t, temporal_sampling_comparison_t, and sampling_flags_t. But aren't the first two sampling flags (or sampling options)?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I think combining them would make sense, let me look at that.

* is required and @p fan_out contains one value per (hop, edge type). Otherwise, @p fan_out
* contains one value per hop.
*
* RANDOM selection samples uniformly when @p edge_bias_view is absent and samples according to

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.

RANDOM=>neighbor_selection_t::RANDOM?

or something like

neighbor_selection_t dictates a neighbor selection method. RANDOM selection samples ... ?

And documentation for template and input parameters and return values are missing here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Will look at this

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.

It seems like the documentation still needs updates.

@seunghwak seunghwak left a comment

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.

Additional reviews.

Comment thread cpp/src/c_api/neighbor_sampling.cpp Outdated
return cugraph::c_api::run_algorithm(graph, functor, result, error);
auto const* options_cpp =
reinterpret_cast<cugraph::c_api::cugraph_sampling_options_t const*>(options);
return cugraph_neighbor_sample(

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.

Any reason the biased wrappers call run_neighbor_sample() (https://github.com/rapidsai/cugraph/pull/5625/changes#diff-d268da7d4ce7574a739c9818704be440c1d2d633f087c39f8a73736b2f057859R746) directly while the uniform wrappers go through cugraph_neighbor_sample()? Better be more consistent about call chains?

It is a bit challenging to understand the call stack hierarchy.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This all should go through cugraph_neighbor_sample, I'll fix that. I tried a few things and ended up with this model, missed getting rid of some of the run_neighbor_sample() calls.

The intention is to remove the old interfaces and have everything call cugraph_neighbor_sample, but I wanted to marek them as deprecated and leave the old methods in place for a release before we delete them.

* SPDX-License-Identifier: Apache-2.0
*/

// Built into libcugraph_common.so: sampling common TUs (gather_one_hop / sample_outgoing_edges)

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.

This seems to describe a build/linkage requirement rather than the implementation itself. Would it be better to keep this explanation in CMakeLists.txt next to where these sources are added to CUGRAPH_COMMON_*?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'll move that.

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.

Sounds great.

Comment thread cpp/src/c_api/neighbor_sample.cpp Outdated
auto options =
*reinterpret_cast<cugraph::c_api::cugraph_sampling_options_t const*>(sampling_options);

auto const is_biased = edge_biases != nullptr;

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.

What happens when we're using the legacy functions (i.e. homogeneous_biased_temporal_neighbor_sample) and don't have a way to pass edge biases from PLC? It seems like it will just fall back to uniform neighbor sampling which we don't want. This PR needs to expose a way to pass the biases from PLC, or at least to preserve the old behavior while we work that out in a separate PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch. I forgot that we don't yet have a good way of creating a biases array except as the edge weights when we create the graph. I'll add that back.

@seunghwak seunghwak left a comment

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.

Comments about several minor cosmetic issues. Otherwise, LGTM.

* is required and @p fan_out contains one value per (hop, edge type). Otherwise, @p fan_out
* contains one value per hop.
*
* RANDOM selection samples uniformly when @p edge_bias_view is absent and samples according to

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.

It seems like the documentation still needs updates.

Comment thread cpp/src/c_api/neighbor_sample.cpp Outdated
}

// FIXME: For biased sampling, the user should pass either biases or edge weights,
// otherwised throw an error and suggest the user to call uniform neighbor sample instead

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.

Any reason to delay addressing this?

@ChuckHastings ChuckHastings Aug 18, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. The comment was mostly obsolete, but added another CUGRAPH_EXPECTS to catch the edge case that was still wrong.

};

// FIXED_WINDOW analogue of thrust::maximum / thrust::minimum used to dedupe scalar side-table
// times: duplicate entries for the same key are expected to be identical, so keep the first.

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.

Minor documentation issue but we are migrating from thrust::minimum/maximum to cuda::minimum/maximum.

sorted_times.begin(),
thrust::make_zip_iterator(out_majors.begin(), out_labels.begin()),
out_times.begin(),
thrust::equal_to<cuda::std::tuple<vertex_t, int32_t>>{},

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.

cuda::std::equal_to.

sorted_times.begin(),
out_majors.begin(),
out_times.begin(),
thrust::equal_to<vertex_t>{},

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.

cuda::std::equal_to

* SPDX-License-Identifier: Apache-2.0
*/

// Built into libcugraph_common.so: sampling common TUs (gather_one_hop / sample_outgoing_edges)

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.

Sounds great.

@ChuckHastings
ChuckHastings requested a review from a team as a code owner August 18, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improvement / enhancement to an existing function non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Temporal sampling: support a fixed per-seed cutoff across hops

3 participants