Skip to content

Roadef - #26

Closed
legraina wants to merge 46 commits into
mainfrom
roadef
Closed

Roadef#26
legraina wants to merge 46 commits into
mainfrom
roadef

Conversation

@legraina

@legraina legraina commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

No description provided.

legraina and others added 30 commits March 10, 2026 12:00
Extract DFS-with-backtracking machinery shared by Greedy and Tabu into a
new BacktrackingDiveAlgorithm base, owning path_, dive primitives
(extend_label, backtrack), path lifecycle, and a child_comparator hook.

Pull tabu-list bookkeeping shared by TabuSearchAlgorithm and
DiversificationSearch (arc_id->tenure map, adaptive extra tenure with
optional jitter, aging with optional on-expire callback, grow/shrink)
into a new TabuList helper used by composition in both.

New TabuSearchAlgorithm: peer of GreedyAlgorithm, episodic dives with
arc tabu memory + aspiration. Customises only select_children and
main_loop.

child_comparator on the base: when graph_->are_nodes_sorted(), prefer
forward arcs (destination pos > parent pos) before backward ones; within
each group, cost-ascending. Both Greedy and Tabu inherit this so dives
follow the user-supplied node ordering's intended tour layout instead of
jumping cheaply but late and having to backtrack to early required.

Slim refactor of GreedyAlgorithm onto the new base. DiversificationSearch
now uses TabuList. Minor tweaks in dominance_algorithm.hpp and
pulling_dominance_algorithm.hpp to align with the refactor.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…er based on size, Add a solver status, Add a pointer to the previous label with a ref count to easily rebuild a path.
- Replace std::list<size_t> with std::vector<size_t> for
  Solution::path_node_ids/path_arc_ids and VRP Path::visited_nodes,
  eliminating cache-hostile linked-list traversal on the hot path.
- Extend CI matrix to test Python 3.11/3.12/3.13 on macOS and Linux
  with pytest --tb=short; exclude Debug builds for 3.11 and 3.13.
- Add py.typed PEP 561 marker and _core/*.pyi stub files so IDEs
  provide autocompletion for all C++-backed types.
- Update CMakeLists.txt to copy and install .pyi and py.typed alongside
  the Python package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Four improvements to LabelBuckets<BucketResource, SortResource, ResourceType>:

1. buckets_ list → vector: cache-friendly bucket iteration and random-access
   indexing required by the binary search helpers below.

2. O(log B) bucket lookup: find_first_not_after / find_first_before binary-
   search helpers replace the O(B) linear scans in add_label (find insertion
   bucket), remove_dominated_labels (find first relevant bucket), and
   is_dominated (find last relevant bucket).

3. O(1) erase_label: begin_label_to_bucket_idx_ (unordered_map<Label*, size_t>)
   maps each current bucket-begin label to its bucket index. A single map
   lookup replaces the O(B) std::find_if scan over all bucket begins. The map
   is maintained by insert_bucket / remove_bucket / update_bucket_begin (O(B)
   index-shift cost there, but bucket operations are O(B) total vs. O(N)
   erase_label calls).

4. Symmetric instrumentation: num_dom_labels_ / num_dom_visited_ counters added
   to is_dominated (mirroring the existing remove_dominated stats). print_labels
   reports both visit ratios. Also exposes suggest_range(target_buckets) which
   uses the peak simultaneous bucket count to estimate the resource spread and
   suggest a calibrated range_buckets for subsequent phases.

Bug fixed during implementation: the ++removed increment in
remove_dominated_labels was placed after the break that fires when a full
bucket is emptied, causing dominated labels to go uncounted in that path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add four unit tests covering binary-search and map-maintenance code paths
(RemoveDominatedMultiBucket, IsDominatedMultiBucket, EraseBeginMultiBucket,
SuggestRange). Add BucketS and BucketP benchmark columns by running a second
independent solve per instance with LabelBuckets + SimpleDominanceAlgorithm
and PullingDominanceAlgorithm.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r_each_arc non-const overload

- ExtraSolver type-erased struct + run_algorithm public wrapper enable
  bucket-container algorithms to participate in the same CG solve as
  list-container algorithms, sharing duals and cross-checking costs
- run_boost normalized at top of solve; warns + disables if Boost not
  compiled in; drives num_total_algos and algo_index correctly
- collect_solutions cross-checks costs (not counts) between optimal algos
- benchmark uses --boost flag; bucket algorithms run as ExtraSolvers
- Graph::for_each_arc gains non-const overload for update_reduced_costs
- CMakeLists: Boost optional at compile time via RCSPP_VRP_HAS_BOOST

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…container

Parent-pointer O(hops) reconstruction:
- Label gains public parent_ and child_refcount_ fields (initialized to
  null/0 in both constructors and reset_label)
- LabelPool::release_label checks child_refcount_; if > 0, defers
  recycling. do_release() cascades up the parent chain when a label's
  last child is gone, avoiding any zombie memory retention
- DominanceAlgorithm::extend_label sets parent_ and bumps child_refcount_
  only when the child survives feasibility and dominance checks
- get_path_arc_ids replaced with a simple parent-pointer walk
- GreedyAlgorithm unaffected: never calls DominanceAlgorithm::extend_label

AlgorithmBaseParams::with_container:
- Forward-declare AlgorithmParams before AlgorithmBaseParams so the
  member function template can name its return type
- Define with_container out-of-line after AlgorithmParams is complete
- Allows: base.with_container<LabelList<RT>>() or
  base.with_container(std::move(bucket_container))

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace ternary-constructed vector with a base vector + conditional
insert, making the Boost column addition easier to read.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rkflow

SolveResult:
- Template VRP::solve() now returns SolveResult{timers, lp_cost} instead
  of a bare vector; lp_cost is the final master LP objective after CG

benchmark_common.hpp (new, shared by both benchmark binaries):
- kSolomonBKS: inline map of BKS values for C1/R1/RC1/C2/R2/RC2
- format_benchmark_table(): prints Instance | LP Cost | Gap% | per-algo HH:MM:SS
  Gap% = (lp_cost - bks) / bks * 100; flags FAIL if lp_cost > bks + 1e-3
  Total row accumulates timers; cost/gap columns show '-' there

benchmark_main.cpp (C1/R1/RC1, formerly print_timer_table):
- Uses structured binding auto [timers, lp_cost] = vrp.solve<...>(...)
- Collects rows and prints one table at the end via format_benchmark_table

benchmark_large_main.cpp (new, C2/R2/RC2 + Gehring & Homberger):
- run_vrp() helper avoids duplication; shares all algorithm setup
- --r2-max N: override R2 instance count (R2 has 11, C2/RC2 have 8)
- --gh-dir path: scan a directory of Solomon-format .txt files for
  Gehring & Homberger 200-1000-customer instances

CMakeLists.txt: add rcspp-vrp-benchmark-large target; exclude both
benchmark_*_main.cpp from the shared SOURCE_FILES glob

.github/workflows/benchmark.yml (new):
- workflow_dispatch with inputs: max_instances, run_large, max_large_instances
- Builds Release, runs small and optionally large benchmark
- Uploads results as artifacts keyed by commit SHA
- NOTE: Gurobi must be available on the runner

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add MemoryInfo struct (cross-platform RSS / available / total RAM)
- Add MemoryLimitHelper struct (resolve + is_exceeded + is_under_pressure)
  both live in utils/memory.hpp; MemoryLimitHelper takes plain values so
  it has no dependency on AlgorithmBaseParams
- Add kKB / kMB / kGB / kDefaultMemoryPressureFraction to memory.hpp
- Add AlgorithmBaseParams memory fields: max_memory_gb, limit_to_available_ram,
  limit_to_total_ram, memory_limit_fraction, memory_check_interval,
  memory_pressure_fraction, memory_pressure_max_labels_per_node
- Add effective_max_labels_per_node_ and memory_pressure_triggered_ to Algorithm
- Add virtual on_memory_pressure() and release_label_memory() hooks
- Implement on_memory_pressure() in Simple / Pushing / Pulling algorithms:
  tightens per-node cap, two-phase trim (store aside then release)
- Call release_label_memory() at end of every solve() to reclaim RSS
- Add LabelPool::release() (clear + shrink_to_fit)
- Add ResourceGraph::solve(AlgorithmBaseParams, ...) overload
- Add 12 new tests (4 templates x 3 algorithm types):
  MemoryLimitImmediateStop, MemoryLimitAvailableRam, MemoryLimitTotalRam,
  MemoryPressurePruning
- Extend .gitignore to cover build_*/ directories
- Exclude build directories from markdownlint pre-commit hook
- Move fstream/string includes to top of memory.hpp for cpplint IWYU

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the per-row std::vector<Row>{one_element} construction pattern
(N malloc/free pairs) with a single-pass approach over arc_id runs:

- Rows array arrives pre-sorted by arc_id (guaranteed by the Python caller).
- Loop advances j to find the end of each run, reserves capacity once
  per arc (dr.reserve), then push_back-fills directly — no temporary
  vector, no repeated heap allocations.

For N_rows rows across N_arcs arcs this reduces:
  old: N_rows × (1 malloc + 1 free + 1 push_back + bounds check)
  new: N_arcs × 1 reserve  +  N_rows × 1 push_back

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MemoryLimitHelper::resolve() is called on every G.solve() invocation.
With LOG_INFO, a run with thousands of pricing calls emits an identical
'Memory limit: X GB (explicit).' line for each one, flooding the logs.

Demote all resolve() log messages to LOG_DEBUG — they remain visible
when debug logging is enabled but are silent in normal operation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each resolve() debug message now appends the current process RSS
(from MemoryInfo::process_bytes()):

  'Memory limit: 2 GB (explicit); process RSS: 312 MB.'

This makes the message immediately actionable when debugging OOM or
early-exit situations — no need to correlate with an external profiler.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolved merge conflicts between quick-improvements (HEAD) and tight-lb,
preferring HEAD's changes when uncertain:

- Keep HEAD's memory-limit infrastructure (MemoryLimitHelper, max_memory_gb,
  memory_check_interval, memory_pressure_fraction, etc.)
- Keep HEAD's AlgorithmBaseParams / AlgorithmParams struct hierarchy
- Keep HEAD's ResourcePrototype-based Resource class architecture
- Adopt tight-lb's prev_label/ref_count/pending_release label tracking
  (replacing parent_/child_refcount_) to match staged code
- Adopt tight-lb's release_with_ref_count() cascade in LabelPool
- Integrate tight-lb's new algorithms: BacktrackingDiveAlgorithm,
  TabuList, TabuSearch (added files)
- Keep HEAD's DiversificationSearch logic, use tight-lb's TabuList member
- Fix duplicate fast_check_dominance overload in dominance_function.hpp
- Fix stray tolerance field usage in dominance_algorithm.hpp

All 46 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
legraina and others added 16 commits May 28, 2026 00:17
…lve to algorithm

- Introduce AlgorithmStatus enum (COMPLETE, TIMEOUT, MAX_SOLUTIONS, MAX_PHASES,
  INTERRUPTED, MEMORY_LIMIT) and SolveResult struct wrapping solutions + status
- Add timeout_s, tolerance, and release_after_solve to AlgorithmBaseParams;
  release_after_solve=false avoids shrink_to_fit overhead in tight inner loops
  (e.g. DiversificationSearch)
- Add is_time_out() and should_stop(iteration) helpers to Algorithm base class
- Update ResourceGraph::solve() to return SolveResult; fix backtracking_dive
  get_path_arc_ids return type (std::list -> std::vector); rename vrp SolveResult
  to CGSolveResult to avoid namespace collision
- Expose AlgorithmStatus, SolveResult, timeout_s, tolerance, release_after_solve
  in Python bindings; add sequence protocol to SolveResult for backward compat

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add cmake-build-*/ for CLion build directories
- Add *.so / *.dylib for macOS/Linux shared library outputs
- Add .venv/, .pytest_cache/, .claude/ (were relying on self-ignoring .gitignore
  inside those dirs; make project intent explicit)
- Remove 306 previously-tracked files from build_asan/ and build_py/ that
  were committed before the build_*/ ignore rule was in place

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The tabu while-loop checked max_iterations, stop_after_X_solutions and
is_interrupted() but not is_time_out(), so params.timeout_s had no
effect on the tabu search. Add !is_time_out() to the condition so a
wall-clock deadline (e.g. tabu_timeout_s=0.5s) is honoured inside the
loop rather than only after main_loop() returns.

Without this fix the tabu solver could run indefinitely on pathological
graph configurations, blocking worker processes and stalling the parent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements A*-style label-correcting that replaces the FIFO frontier
with a min-heap ordered by f = g + h, where h is a per-node admissible
lower bound computed via a backward Bellman-Ford pass using arc costs.
The heuristic is resource-type-agnostic to avoid template instantiation
issues with mixed resource compositions (int+bitset, int+set, etc.).

Registers the algorithm as Algorithm.AStar / "astar" in the Python
bindings and adds it to both VRP benchmarks and the full test suite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AStarDominanceAlgorithm now uses the same cost resource as the labeling
algorithm (via a new CostResourceType 3rd template param) to compute
the backward Bellman-Ford heuristic h(n). This puts g and h on the same
scale — both use reduced costs — making f = g + h a meaningful lower
bound on the total path cost.

Key changes:
- BellmanFordAlgorithm: extract the loop into run_relaxations(); add a
  clean arc-cost-only solve(graph, ids, bool) overload that avoids the
  CostResourceType template constraint issue across all compositions
- AStarDominanceAlgorithm: add CostResourceType as 3rd template param
  (default RealResource); use if constexpr + is_cost_in_composition_v
  to call the resource-based Bellman-Ford when the type is present,
  arc-cost fallback otherwise; catch negative-weight cycles (possible
  with reduced costs) and fall back to arc.cost
- graph_impl.hpp: AStarAlgoBound<CostRC> presents the 3-param algo as
  a 2-param template; AStarAlgoEntry injects cost_index into params and
  binds the correct CostRC at dispatch time
- algorithm.hpp: add heuristic_cost_index to AlgorithmBaseParams
- resource_traits.hpp: add is_cost_in_composition_v trait and the
  missing resource_type_composition.hpp include

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AStarDominanceAlgorithm now has 3 template params so it no longer
satisfies template<typename,typename>; replace with the 2-param wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tar flag

New ImprovingTabuSearch algorithm (two-phase):
  1. GreedyAlgorithm with infinite upper bound finds an initial feasible
     solution and its cost
  2. TabuSearchAlgorithm uses that cost as the upper bound and improves

Benchmark changes (both benchmark_main and benchmark_large_main):
- Replace the single "Diversif" extra solver with two named heuristics:
    ConstructiveTabu = DiversificationSearch (arc-removal diversification)
    Tabu             = ImprovingTabuSearch (greedy init + tabu improvement)
- AStar is now optional behind --astar (off by default because it is slow);
  it runs as an extra solver rather than a main CG algorithm so it does
  not penalise the default benchmark run
- Remove AStarAlgoBound from the vrp.solve<> template pack; main CG
  algorithms are back to Simple / Pushing / Pulling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrites ImprovingTabuSearch as a self-contained BacktrackingDiveAlgorithm
subclass (same base as TabuSearchAlgorithm) rather than a sequenced pair of
separate algorithm objects:

Phase 1 — construction (tabu inactive):
  A pure greedy dive finds the initial feasible solution and records its
  cost as the starting upper bound for the improvement phase.

Phase 2 — improvement (tabu active):
  Repeated tabu-filtered dives constrained to the current best cost.
  Classical TS mechanisms:
  - Tabu list: arcs of the last found path are forbidden for tabu_tenure
    iterations to prevent cycling.
  - Aspiration criterion: when all extensions from a node are tabu, the
    cheapest tabu extension is used anyway (last-resort fallback).
  - Intensification: on a strictly improving solution, shrink_extra() is
    called so the search stays near the good region.
  - Diversification: after diversification_tenure consecutive non-improving
    dives, grow_extra() forces exploration of new regions.

Adds AlgorithmBaseParams::diversification_tenure (default 10) to control
the diversification threshold.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace manual loop conditions with the unified should_stop(i) helper in
both TabuSearchAlgorithm and ImprovingTabuSearch, and remove stray blank
lines in the latter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

# Conflicts:
#	src/rcspp/algorithm/tabu_search.hpp
# Conflicts:
#	src/python_interface/CMakeLists.txt
#	src/rcspp/algorithm/algorithm.hpp
#	src/rcspp/algorithm/dominance_algorithm.hpp
#	src/rcspp/algorithm/solution.hpp
#	src/rcspp/rcspp.hpp
dive_to_sink() in the tabu searches (and greedy extend) is a DFS with
backtracking; on pathological (demand, duals) combos a single dive
enumerates exponentially many partial paths, and all per-iteration
should_stop() checks sit between dives, so timeout_s/max_iterations
never fire — one solve wedged a pricing worker for 15+ minutes.

- greedy.hpp, tabu_search.hpp, improving_tabu_search.hpp: poll
  is_time_out() || is_interrupted() every 4096 dive steps.
- pulling_dominance_algorithm.hpp: main_loop now uses should_stop(i)
  (timeout + interrupt + budgets) like the base DominanceAlgorithm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each dive extension allocates a label, so a pathological dive is an RSS
runaway as well as a time sink: a setB-01 pricing worker grew 4 to 8 GB
in 11 s while its max_memory_gb was 2.67 GB, because only the dominance
main loops consulted MemoryLimitHelper. The every-4096-steps poll in
greedy/tabu/improving-tabu dives now also checks is_exceeded().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 21:34

Copilot AI 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.

Pull request overview

This PR expands the RCSPP/VRP stack with new solver variants (A* dominance, tabu heuristics), adds memory-limit/timeout-aware stopping with explicit solve status reporting, and updates the VRP benchmarking harnesses and Python bindings to expose the new capabilities.

Changes:

  • Introduces SolveResult/AlgorithmStatus and memory/timeout-based early-stop mechanics across algorithms, plus new heuristic algorithms (tabu variants) and an A*-ordered dominance algorithm.
  • Updates VRP column-generation plumbing (optional Boost build, heterogeneous “extra solvers”, richer VRP::solve() result) and adds/extends benchmark executables and formatting.
  • Extends Python bindings/stubs and CI workflows to cover new algorithms and runtime features.

Reviewed changes

Copilot reviewed 56 out of 58 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/rcspp/vrp_subproblem/vrp_subproblem.hpp Passes base algorithm parameters into test VRP subproblem RCSPP solves and guards empty solution logging.
tests/rcspp/test_rcspp.hpp Adds A* dominance coverage plus new memory-limit behavior tests.
tests/rcspp/test_label_buckets.hpp Adds multi-bucket correctness tests and suggest_range() coverage for LabelBuckets.
src/vrp/vrp.hpp Adds CGSolveResult, optional Boost execution, extra solver support, and a run_algorithm() helper.
src/vrp/vrp.cpp Makes Boost subproblem compilation optional and adjusts path container type.
src/vrp/main.cpp Makes Boost include optional for builds without Boost.
src/vrp/CMakeLists.txt Makes Boost optional, filters Boost-only sources when absent, and adds a large benchmark target.
src/vrp/cg/path.hpp Switches Path::visited_nodes from std::list to std::vector.
src/vrp/cg/path.cpp Updates Path constructor signature to accept std::vector.
src/vrp/benchmark_main.cpp Refactors benchmarking to shared formatting, adds optional Boost/A* flags, and integrates extra solvers.
src/vrp/benchmark_large_main.cpp Adds a large-instance benchmark driver for Solomon C2/R2/RC2 and optional GH instances.
src/vrp/benchmark_common.hpp Adds shared benchmark table formatting and Solomon BKS-based gap reporting.
src/rcspp/utils/memory.hpp Adds cross-platform memory queries and a helper for resolving/enforcing memory limits.
src/rcspp/resource/resource_traits.hpp Adds a trait to detect whether a cost resource is present in a composition.
src/rcspp/resource/resource_graph.hpp Changes solve() to return SolveResult and adds an overload accepting AlgorithmBaseParams.
src/rcspp/resource/concrete/numerical_resource.hpp Adds delta-aware comparisons and simplifies self-type references.
src/rcspp/rcspp.hpp Exposes new algorithms and memory utilities via the umbrella include.
src/rcspp/preprocessor/connectivity_matrix.hpp Extends SCC adjacency construction to include in-arc origins.
src/rcspp/preprocessor/bellman_ford_algorithm.hpp Refactors Bellman–Ford into reusable relaxation logic and overloads for arc-cost vs resource-cost.
src/rcspp/label/label.hpp Adds predecessor pointer + ref-count based pinning for path reconstruction.
src/rcspp/label/label_pool.hpp Implements ref-count-aware release cascading and adds full pool release() reclamation.
src/rcspp/label/label_factory.hpp Resets new predecessor/ref-count fields on label reset.
src/rcspp/graph/graph.hpp Adds a mutable for_each_arc overload.
src/rcspp/algorithm/tabu_search.hpp Adds a constructive tabu-search algorithm based on backtracking dives.
src/rcspp/algorithm/tabu_list.hpp Adds reusable tabu tenure bookkeeping shared by tabu-style algorithms.
src/rcspp/algorithm/simple_dominance_algorithm.hpp Adds memory-pressure trimming behavior and uses an effective per-node cap.
src/rcspp/algorithm/pushing_dominance_algorithm.hpp Adds memory-pressure trimming and uses effective per-node caps; includes missing <list>.
src/rcspp/algorithm/pulling_dominance_algorithm.hpp Adds stop-condition coverage and periodic memory checks + trimming.
src/rcspp/algorithm/label_buckets.hpp Refactors LabelBuckets to vector-backed buckets with O(log B) search, O(1) erase bookkeeping, and instrumentation.
src/rcspp/algorithm/improving_tabu_search.hpp Adds a two-phase improving tabu search heuristic with diversification control.
src/rcspp/algorithm/greedy.hpp Uses unified stop checks and adds periodic timeout/interrupt/memory polling in deep backtracking.
src/rcspp/algorithm/dominance_algorithm.hpp Adds memory checks, ref-count-aware label release, and O(hops) path reconstruction via predecessor pointers.
src/rcspp/algorithm/diversification_search.hpp Replaces bespoke tabu bookkeeping with TabuList and adapts to SolveResult.
src/rcspp/algorithm/backtracking_dive_algorithm.hpp Adds shared DFS/backtracking machinery for constructive heuristics.
src/rcspp/algorithm/astar_dominance_algorithm.hpp Adds A*-ordered dominance algorithm with Bellman–Ford heuristic and memory-pressure trimming.
src/rcspp/algorithm/algorithm.hpp Introduces SolveResult/AlgorithmStatus, timeout/memory-limit parameters, and unified stop logic with optional pool release.
src/python/test_vrp.py Makes Python tests import the interface via stable paths relative to the test file.
src/python/test_rcspp.py Adds A* usage examples and bucket params position-based API tests; stabilizes import paths.
src/python/test_rcspp_networkx.py Stabilizes import paths for networkx integration tests.
src/python/test_graph.py Makes numpy optional via pytest.importorskip and stabilizes import paths.
src/python/test_clone.py Makes numpy optional via pytest.importorskip, renames dual-rows wording to rows, and stabilizes import paths.
src/python_interface/rcspp/solution_pool.cpp Clarifies control flow in pruning predicate with explicit braces.
src/python_interface/rcspp/rcspp.cpp Exposes process/available memory byte helpers in the Python extension module.
src/python_interface/rcspp/py.typed Marks the Python package as typed.
src/python_interface/rcspp/graph.py Adds algorithm aliases, returns SolveResult, and introduces a Python BucketAlgorithmParams wrapper with pos-based resource selection.
src/python_interface/rcspp/graph.cpp Exposes new enums (AlgorithmStatus) and SolveResult, and binds new algorithm params fields.
src/python_interface/rcspp/graph_impl.hpp Updates dispatch to return SolveResult, adds Tabu/A* dispatch entries, and optimizes bulk row insertion.
src/python_interface/rcspp/_core/resource.pyi Adds typing stubs for resource-related extension/feasibility/cost/dominance helpers.
src/python_interface/rcspp/_core/logger.pyi Adds typing stubs for logger API.
src/python_interface/rcspp/_core/graph.pyi Adds typing stubs for graph API including SolveResult and algorithm parameters.
src/python_interface/rcspp/_core/init.pyi Adds typing stub package exports for _core.
src/python_interface/rcspp/init.py Re-exports AlgorithmStatus, SolveResult, and memory helper functions from the extension.
src/python_interface/CMakeLists.txt Installs .pyi and py.typed files and ensures they are copied during builds.
instances/RC201_12.txt Adds a Git LFS pointer for a new instance artifact.
.pre-commit-config.yaml Excludes build directories from markdownlint hook.
.gitignore Expands ignore rules for build artifacts and Python caches/venvs.
.github/workflows/ci.yml Expands test matrix to Python 3.11–3.13 and tweaks pytest output.
.github/workflows/benchmark.yml Adds a manually-triggered benchmark workflow (small + optional large benchmark).
Suppressed comments (4)

src/vrp/vrp.hpp:146

  • Same issue here: prefer std::abs for double differences to avoid relying on unqualified overload resolution.
    src/rcspp/algorithm/astar_dominance_algorithm.hpp:186
  • When trimming under memory pressure, labels are released via release_label but may still be referenced as predecessors. Use release_with_ref_count consistently for any label allocated in DominanceAlgorithm-derived runs.
            if (this->memory_pressure_triggered_) {
                for (auto& [label_ptr, label_iter] : unprocessed_truncated_labels_) {
                    this->remove_label(label_iter);
                    this->label_pool_.release_label(label_ptr);
                }

src/rcspp/algorithm/astar_dominance_algorithm.hpp:220

  • Dominated excess labels are recycled with release_label, which ignores the new predecessor pinning mechanism. Use release_with_ref_count here as well.
            for (size_t i = max_total; i < flat.size(); ++i) {
                auto& p = flat[i];
                if (p.first->dominated) {
                    this->label_pool_.release_label(p.first);
                } else {

src/vrp/vrp.hpp:113

  • Unqualified abs(diff) on a double can resolve to the integer overload depending on headers/toolchain. Prefer std::abs (and include <cmath>).

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

Comment thread src/vrp/vrp.hpp
Comment on lines +6 to 9
#include <functional>
#include <limits>
#include <optional>

Comment on lines +134 to +136
if (label_iterator_pair.first->dominated) {
this->label_pool_.release_label(label_iterator_pair.first);
} else {
Comment thread src/rcspp/label/label.hpp
Comment on lines +85 to +88
Label<ResourceType>* prev_label = nullptr;
// Number of alive successors that reference this label as their predecessor.
uint8_t ref_count = 0;
// True when the algorithm wanted to release this label but ref_count was > 0.
Comment on lines +6 to +12
#include <cmath>
#include <iomanip>
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>
Comment on lines +8 to +14
class Algorithm(Enum):
Simple: Algorithm
Pushing: Algorithm
Pulling: Algorithm
Greedy: Algorithm
Tabu: Algorithm

@legraina legraina closed this Aug 3, 2026
@legraina
legraina deleted the roadef branch August 3, 2026 21:16
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.

3 participants