Skip to content

feat: add greedy lookahead algorithm with rolling horizon for hyperpixel building#9

Open
dhalmazna wants to merge 6 commits intofeat/algorithm-utilsfrom
feat/lookahead-algorithm
Open

feat: add greedy lookahead algorithm with rolling horizon for hyperpixel building#9
dhalmazna wants to merge 6 commits intofeat/algorithm-utilsfrom
feat/lookahead-algorithm

Conversation

@dhalmazna
Copy link
Collaborator

@dhalmazna dhalmazna commented Mar 16, 2026

Context:
This PR introduces the lookahead.py module, which implements a greedy search algorithm with a rolling horizon strategy for constructing hyperpixels. This serves as a baseline algorithm before we introduce full Monte Carlo search methods.

What's Changed / Added:

  • ciao/algorithm/lookahead.py: Added the implementation of the greedy lookahead builder. It uses bitwise operations and BFS to explore paths.
  • ciao/scoring/hyperpixel.py: Introduced the HyperpixelResult using TypedDict to establish a clear, strict contract for what a built hyperpixel returns.

How it works:

  1. BFS Lookahead: From the current mask, we run a BFS to generate all possible connected supersets up to lookahead_distance steps away.
  2. Batched Evaluation: All generated candidate masks are evaluated in a single forward pass.
  3. Rolling Horizon (Step Committing): We identify the candidate mask with the best score, but we only commit the first step (a single segment) of the path that leads to it. The state is updated, and the process repeats.

@dhalmazna dhalmazna self-assigned this Mar 16, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 13e6c13d-92fd-43ac-8364-ee57bf2fe109

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/lookahead-algorithm
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.

OpenGrep is compatible with Semgrep configurations. Add an opengrep.yml or semgrep.yml configuration file to your project to enable OpenGrep analysis.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request establishes a foundational greedy lookahead algorithm for hyperpixel construction, employing a rolling horizon approach. This new algorithm provides a crucial baseline for evaluating more complex Monte Carlo search methods that will be integrated in the future, ensuring a structured progression in the development of hyperpixel building strategies.

Highlights

  • New Algorithm: Introduced a new greedy lookahead algorithm with a rolling horizon strategy for building hyperpixels, serving as a baseline for future Monte Carlo search methods.
  • File Structure: Added a new module ciao/algorithm/lookahead.py to house the new algorithm and updated README.md to reflect this change and the algorithm's description.
  • Module Export: Exported the build_hyperpixel_greedy_lookahead function from the ciao.algorithm package's __init__.py for external use.
Changelog
  • README.md
    • Updated the description of the 'Lookahead' algorithm to remove the 'using efficient bitset operations' phrase.
    • Corrected the file path reference for the lookahead algorithm from lookahead_bitset.py to lookahead.py.
  • ciao/algorithm/init.py
    • Imported the new build_hyperpixel_greedy_lookahead function.
    • Added build_hyperpixel_greedy_lookahead to the __all__ export list, making it publicly accessible.
  • ciao/algorithm/lookahead.py
    • Added a new Python module implementing the build_hyperpixel_greedy_lookahead function.
    • Implemented a rolling horizon strategy that uses BFS to generate candidate masks up to a specified lookahead_distance.
    • Included a helper function _generate_lookahead_candidates to perform the BFS for connected supersets.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a greedy lookahead algorithm, which is a solid addition as a baseline for hyperpixel construction. The implementation is well-structured, with a clear separation between the main building loop and the candidate generation logic. The use of a rolling horizon strategy is correctly implemented. My main suggestion is to use TypedDict for the return type to improve type safety and code clarity, which is a lightweight improvement over the current dict[str, object] while you plan for a future refactor to a dataclass.

@dhalmazna dhalmazna marked this pull request as ready for review March 16, 2026 15:52
Copilot AI review requested due to automatic review settings March 16, 2026 15:52
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a greedy lookahead algorithm for building hyperpixels using a rolling horizon strategy (BFS lookahead + commit-one-step), along with a HyperpixelResult TypedDict to formalize the return contract of hyperpixel builders.

Changes:

  • New ciao/algorithm/lookahead.py implementing BFS-based greedy lookahead with rolling horizon for hyperpixel construction.
  • New HyperpixelResult TypedDict in ciao/scoring/hyperpixel.py and migration of select_top_hyperpixels to use it (including renaming the sort key from hyperpixel_score to score).
  • README and __init__.py updates to reflect the new module.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
ciao/algorithm/lookahead.py New greedy lookahead builder using BFS candidate generation and rolling horizon commit strategy
ciao/scoring/hyperpixel.py Added HyperpixelResult TypedDict; updated select_top_hyperpixels to use it
ciao/algorithm/__init__.py Re-exports the new build_hyperpixel_greedy_lookahead function
README.md Updated algorithm description and file tree to reflect the renamed module

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +169 to +210
def _generate_lookahead_candidates(
current_mask: int,
adj_masks: tuple[int, ...],
used_mask: int,
lookahead_distance: int,
desired_length: int,
) -> dict[int, int]:
"""Generate all connected supersets up to lookahead_distance steps via BFS.

Returns:
Dict mapping candidate_mask -> first_step_segment_id
"""
candidates: dict[int, int] = {} # mask -> first_step

# Queue stores tuples of: (current_mask, first_step_that_led_here, current_depth)
queue: deque[tuple[int, int | None, int]] = deque([(current_mask, None, 0)])
visited = {current_mask}

while queue:
mask, first_step, depth = queue.popleft()

# Store valid candidates (depth > 0)
if depth > 0 and first_step is not None and mask not in candidates:
# Only add if not already seen (shortest path wins)
candidates[mask] = first_step

# Stop expanding if we reached the lookahead limit or maximum size
if depth >= lookahead_distance or mask.bit_count() >= desired_length:
continue

frontier = get_frontier(mask, adj_masks, used_mask)
for seg_id in iter_bits(frontier):
new_mask = add_node(mask, seg_id)

if new_mask not in visited:
visited.add(new_mask)
# If at the first layer (depth 0), this seg_id is our first_step.
# Otherwise, pass along the first_step inherited from the parent.
next_first_step = seg_id if depth == 0 else first_step
queue.append((new_mask, next_first_step, depth + 1))

return candidates
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's the user's problem if he sets the lookahead_distance too large :D

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.

2 participants