Skip to content

Segment tree#31

Merged
lrleon merged 11 commits intomasterfrom
segment-tree
Feb 10, 2026
Merged

Segment tree#31
lrleon merged 11 commits intomasterfrom
segment-tree

Conversation

@lrleon
Copy link
Copy Markdown
Owner

@lrleon lrleon commented Feb 10, 2026

Summary by CodeRabbit

  • New Features

    • Added multiple segment-tree variants (standard, lazy, and "beats") with rich APIs for updates and queries.
  • Documentation

    • Expanded guides, examples, and API reference for the new segment-tree types.
  • Examples

    • Added a segment-tree example program demonstrating real-world usage.
  • Tests

    • Comprehensive unit tests and a new test executable covering functionality and stress scenarios.
  • Chores

    • Exposed an additional public header; removed obsolete test helper and dependency scripts.

Copilot AI review requested due to automatic review settings February 10, 2026 02:05
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a comprehensive segment-tree header (tpl_segment_tree.H) implementing standard, lazy (policy-driven), and Beats variants; exposes the header in CMake, adds example and test targets, expands README with documentation and examples, introduces extensive unit tests, and removes two test utility scripts.

Changes

Cohort / File(s) Summary
Core Library Implementation
tpl_segment_tree.H
New public header implementing Gen_Segment_Tree (generic), Sum/Min/Max aliases, Gen_Lazy_Segment_Tree (policy-based lazy updates) with concrete policies, and Segment_Tree_Beats. Adds constructors, public APIs (update/set/query/get/values/size/swap), internal helpers, and template concepts/types.
Build Configuration
CMakeLists.txt, Examples/CMakeLists.txt, Tests/CMakeLists.txt
Expose tpl_segment_tree.H in public headers (HLIST); add segment_tree_example to example programs; add tpl_segment_tree_test to test programs.
Documentation & Examples
README.md
Extensive README additions documenting segment tree variants, usage examples, API reference entries, and example program indexing (references segment_tree_example.cc).
Test Suites
Tests/tpl_segment_tree_test.cc, Tests/tpl_sparse_table_test.cc
Add extensive unit tests: tpl_segment_tree_test.cc covering correctness and stress tests for standard/lazy/beats trees; tpl_sparse_table_test.cc adding sparse-table tests and helpers.
Build/Test Utilities
Tests/clean, Tests/depend.sh
Removed a cleanup action from Tests/clean and deleted Tests/depend.sh (custom dependency-generation script).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Header Docstring Coverage ⚠️ Warning The file tpl_segment_tree.H introduces 13 public classes and structs with zero Doxygen-style documentation comments (/// or /**), resulting in 0% documentation coverage against the required 80% threshold. Add Doxygen-style documentation (/// or /**) for all 13 public classes/structs including Gen_Segment_Tree, Gen_Lazy_Segment_Tree, and Segment_Tree_Beats, documenting purpose, key methods, and parameter semantics.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Segment tree' directly and accurately summarizes the main change: adding comprehensive segment tree implementations and related test coverage to the library.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch segment-tree

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.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 10, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb89f51dbc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

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

Adds a new segment tree module to Aleph-w, covering classic point-update/range-query segment trees, lazy-propagation segment trees, and Segment Tree Beats, along with tests and README documentation to position segment trees among existing range-query structures.

Changes:

  • Introduces tpl_segment_tree.H with Gen_Segment_Tree, Gen_Lazy_Segment_Tree (policy-based), and Segment_Tree_Beats.
  • Adds comprehensive GTest coverage for segment trees and (separately) sparse tables.
  • Updates build configuration and README to expose the new header and document usage (and references a new example target).

Reviewed changes

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

Show a summary per file
File Description
tpl_segment_tree.H New header implementing three segment tree variants with Doxygen docs.
Tests/tpl_segment_tree_test.cc New GTest suite covering point updates, lazy updates, and Segment Tree Beats.
Tests/tpl_sparse_table_test.cc New GTest suite expanding coverage for sparse tables.
Tests/depend.sh Removed legacy dependency script.
Tests/clean Removed legacy clean script.
Tests/CMakeLists.txt Registers tpl_segment_tree_test in the explicit test list.
README.md Adds segment tree documentation and API table entries.
Examples/CMakeLists.txt Adds segment_tree_example target name (source file not present in this PR).
CMakeLists.txt Adds tpl_segment_tree.H to the header list.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 10, 2026
The `tpl_segment_tree.H` file has been refactored to improve Doxygen documentation for `Gen_Segment_Tree`, `Gen_Lazy_Segment_Tree`, and `Segment_Tree_Beats`. The commit also includes clarifications for `SegmentTreeOp` and new concepts like `SegmentTreePolicy` for lazy segment trees, making the API clearer and more robust. The `query` method in `Gen_Lazy_Segment_Tree` is now `const` due to mutable lazy state, allowing safe calls via `const` references.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tpl_segment_tree.H`:
- Around line 1238-1239: Segment_Tree_Beats is missing a DynList<T> constructor
(unlike Gen_Segment_Tree/Gen_Lazy_Segment_Tree); add a constructor
Segment_Tree_Beats(const DynList<T>& values) that initializes tree and n (use
tree(values.size()==0?1:4*values.size()) and n = values.size()), calls
init_all_nodes(), and when n>0 copies values into a temporary Array<T>
(Array<T>::create(n)) using values.get_it() before calling fill_and_build with a
lambda that returns tmp(j); ensure you reference the existing members tree, n,
init_all_nodes(), fill_and_build(), and Array<T>::create to match other
constructors' behavior and placement (after the std::vector constructor).
🧹 Nitpick comments (6)
tpl_segment_tree.H (6)

216-255: fill_and_build initializes entire tree then overwrites leaves, then rebuilds — redundant O(n) pass.

fill_and_build first initializes all 4*n nodes to identity (line 220–221), then calls fill_leaves_recursive to set leaf values, then calls build to recompute internal nodes. The initial full-array identity fill is unnecessary because fill_leaves_recursive sets every leaf and build recomputes every internal node from its children.

Removing the loop on lines 220–221 would save one O(n) pass over the backing array. The same pattern appears in Gen_Lazy_Segment_Tree::fill_and_build (which already omits it), so the two variants are inconsistent.

♻️ Remove redundant initialization loop
     template <class Getter>
     void fill_and_build(Getter getter)
     {
-      // Initialize entire tree with identity
-      for (size_t i = 0; i < tree.size(); ++i)
-        tree(i) = identity;
-
       // Place values in leaves via recursive descent
       fill_leaves_recursive(1, 0, n - 1, getter);
 
       // Build internal nodes bottom-up
       build(1, 0, n - 1);
     }

430-436: values() is O(n log n) but could be O(n) by traversing leaves directly.

Each get(i) call does a full root-to-leaf query. Since Gen_Segment_Tree has no lazy propagation, you can traverse the implicit tree once to collect all n leaf values in O(n). The same applies to all three tree variants (though the lazy ones need push-down during traversal). Documented complexity is accurate, so this is just an optimization opportunity.


620-637: Clean policy concept — verify std::pair<bool, T> satisfies equality_comparable for Assign_Sum_Policy.

SegmentTreePolicy requires std::equality_comparable<lazy_type>. For Assign_Sum_Policy<T>, lazy_type = std::pair<bool, T>, which is equality-comparable only if T is. This works for arithmetic types but the constraint isn't documented on Assign_Sum_Policy.


1261-1310: pull_up is const but mutates tree(node) — correct only because tree is mutable.

This works, but the const qualifier on pull_up (and push_chmin_to_child, push_chmax_to_child) is semantically misleading since these functions modify observable node state (sum, max_val, etc.), not just cached/lazy metadata. Consider documenting why these are const (the mutable rationale), as per coding guidelines.


1312-1332: push_chmin_to_child is also called on the current node (not a child) in chmin_impl line 1395.

The function name suggests it only operates on children, but it is also called with node itself in the "tag condition" path of chmin_impl. The logic is correct — the function applies a chmin tag to any node regardless of whether it's a child — but the name is misleading. Same for push_chmax_to_child called at line 1414.

Consider renaming to apply_chmin / apply_chmax or adding a brief comment at the call sites.


146-153: Both tree classes use std::vector-style internal storage — consider documenting thread-safety.

Per coding guidelines, thread-safety guarantees should be documented. These segment trees are not thread-safe (concurrent reads on Gen_Lazy_Segment_Tree and Segment_Tree_Beats mutate mutable state via push_down). A brief @note Not thread-safe in the class Doxygen would be helpful.

Also applies to: 844-857

Copy link
Copy Markdown
Contributor

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

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

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 10, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tpl_segment_tree.H`:
- Around line 1561-1564: Segment_Tree_Beats declares its move constructor and
move-assignment as unconditionally noexcept which can mismatch when Array<Node>
move can throw; change both declarations to conditional noexcept like the other
classes (Gen_Segment_Tree / Gen_Lazy_Segment_Tree) so they mirror the move
safety of Array<Node>. Specifically, update the Segment_Tree_Beats move
constructor and operator= to use noexcept(...) that checks Array<Node>'s nothrow
move (e.g. noexcept(std::is_nothrow_move_constructible_v<Array<Node>>) or the
same noexcept(...) expression used in Gen_Segment_Tree/Gen_Lazy_Segment_Tree)
and keep them = default.
🧹 Nitpick comments (7)
tpl_segment_tree.H (7)

146-165: build is called after fill_leaves_recursive redundantly visits leaves.

build recurses to every leaf (start == end) only to return immediately. This is O(n) extra function calls with no work at the leaves. A simple iterative bottom-up loop from n down to 1 on the internal nodes (indices [1, n) in classic 1-based layout) would halve the recursion. Not a correctness issue and the current approach is canonical, so this is purely a performance nit.


216-243: fill_and_build initialises the entire tree to identity, then fills leaves, then rebuilds internal nodes — three passes over the array.

The first pass (lines 220–221) writes identity to all 4*n slots. The second pass (fill_leaves_recursive) overwrites the leaf positions. The third pass (build) recomputes internal nodes. The first pass could be eliminated if build is relied upon to set internal nodes (which it does), and leaves are guaranteed set by fill_leaves_recursive. The only risk is uninitialised internal nodes in the tree array, but Array<T> is already value-initialised in the constructor (Array(size, id)), so the explicit loop is redundant for the size-based constructor and the other constructors that pass id as the fill value.


430-436: values() is O(n log n) — could be O(n) for the non-lazy tree.

Since Gen_Segment_Tree has no lazy propagation, leaf values can be read directly from the backing array by walking the implicit tree to each leaf in a single O(n) traversal, similar to fill_leaves_recursive but reading instead of writing. The current implementation calls get(i) (which is query(i,i) = O(log n)) for each element.

♻️ Sketch: O(n) values extraction
Array<T> values() const
{
  auto ret = Array<T>::create(n);
  extract_leaves(1, 0, n - 1, ret);
  return ret;
}

private:
void extract_leaves(size_t node, size_t start, size_t end,
                    Array<T> & out) const
{
  if (start == end)
    {
      out(start) = tree(node);
      return;
    }
  const size_t mid = start + (end - start) / 2;
  extract_leaves(2 * node, start, mid, out);
  extract_leaves(2 * node + 1, mid + 1, end, out);
}

663-666: Potential integer overflow in Add_Sum_Policy::apply.

delta * static_cast<T>(count) can overflow when T is a narrow type like int and count is large. The same concern applies to Assign_Sum_Policy::apply (line 800) and Segment_Tree_Beats::push_chmin_to_child (line 1320). This is inherent to the algorithm's arithmetic, but consider documenting the overflow risk in the class-level Doxygen (e.g., recommend long long for large inputs).


1244-1261: Consider adding a Doxygen comment to the Node struct.

The Node struct packs quite a few fields. A brief inline comment mapping each field to its role (especially second_max/second_min and the lazy tags) would help maintainers.


1263-1312: pull_up unconditionally resets lazy tags on lines 1310–1311.

pull_up is called after recursive updates that already push_down'd the node's lazy (clearing them). The redundant reset is harmless but slightly misleading — it suggests pull_up owns lazy initialisation. Consider adding a brief comment explaining this is intentional defensive coding, or removing the two lines since the invariant is already maintained by push_down.


1314-1355: push_chmin_to_child / push_chmax_to_child are also called on the node itself (not just children).

In chmin_impl (line 1397) and chmax_impl (line 1416), these functions are invoked with node as the argument — the current node, not a child. The name push_*_to_child is misleading in that context. Consider renaming to apply_chmin / apply_chmax (or apply_chmin_tag / apply_chmax_tag) to clarify that the function applies a clamp operation to any node's statistics and lazy tags.

♻️ Renaming suggestion
-    void push_chmin_to_child(size_t child, T v) const
+    void apply_chmin_tag(size_t node, T v) const
     {
-      auto & nd = tree(child);
+      auto & nd = tree(node);
-    void push_chmax_to_child(size_t child, T v) const
+    void apply_chmax_tag(size_t node, T v) const
     {
-      auto & nd = tree(child);
+      auto & nd = tree(node);

Update all call sites accordingly.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 10, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@tpl_segment_tree.H`:
- Around line 439-445: The swap member is declared unconditionally noexcept but
calls std::swap on identity and op which may throw; change the noexcept
specifier to a conditional expression that reflects whether all swapped members
are nothrow-swappable (e.g. noexcept(std::is_nothrow_swappable_v<decltype(tree)>
&& std::is_nothrow_swappable_v<decltype(n)> &&
std::is_nothrow_swappable_v<decltype(identity)> &&
std::is_nothrow_swappable_v<decltype(op)> ) or use
noexcept(noexcept(std::swap(identity, identity)) && noexcept(std::swap(op, op))
...) so Gen_Segment_Tree::swap, Gen_Lazy_Segment_Tree::swap (and leave
Segment_Tree_Beats::swap as-is if it only swaps noexcept types) only declare
noexcept when the constituent swaps are truly nothrow; update the swap
declarations accordingly.
🧹 Nitpick comments (1)
tpl_segment_tree.H (1)

430-436: values() is O(n log n) but could be O(n) by reading leaves directly.

Each get(i) traverses root-to-leaf. Since the underlying array stores leaf values at known positions, you can extract them in a single O(n) pass. The same applies to Gen_Lazy_Segment_Tree::values() (line 1145) and Segment_Tree_Beats::values() (line 1651) — though the lazy variants would need a full push-down first.

Copy link
Copy Markdown
Contributor

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

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

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