Ng unreacheable - #22
Open
legraina wants to merge 55 commits into
Open
Conversation
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>
…uick-improvements
…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
…into quick-improvements
…cker noise - memory.hpp: clang-format sorted <psapi.h> before <windows.h> (alphabetical), which breaks the Windows build since psapi.h needs DWORD/HANDLE from windows.h. NOLINT only silences cpplint, not clang-format, so wrap the two includes in a clang-format off/on barrier to lock the required order. - __init__.py: apply isort import ordering. - pricing_pool.py: in SharedPricingPool.attach(), use SharedMemory(track=False) on Python 3.13+ so a non-owner worker never registers the segment with the shared resource_tracker. This avoids the benign-but-noisy KeyError tracebacks at interpreter shutdown (owner's unlink() double-unregistering). Falls back to the manual unregister on Python < 3.13. Still spawn-safe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-activate the ng-set resource in the VRP and add an optional dominance strengthening: when a label settles at node j, fold the resource-unreachable members of its ng-neighbourhood N_j into the ng-memory Pi. This is pure acceleration -- the CG LP bound is unchanged while the number of non-dominated labels drops -- and is gated by a per-build flag (default off). Reachability is decided the only general way: by building the trial label L->x along the real arc and checking is_feasible() (reachability couples extension and feasibility; there is no resource-agnostic node-only shortcut). A thread_local re-entrancy guard stops the trial extensions (which reuse the augmented arc extenders) from recursing and makes them measure the plain extension. Dominance stays the standard InclusionDominanceFunction on the augmented Pi -- no separate nu field, no custom dominance. Engine (general, src/rcspp): - Add a post_extend / post_extend_back hook to CompositionExtensionFunction. - New NgUnreachableCompositionExtensionFunction implementing the fold. - Add ResourceGraph::set_composition_extension_function (+ ResourceFactory setter) so a custom composition extension function can be installed. - Expose total_non_dominated_labels() / num_extended_labels() on DominanceAlgorithm. VRP: - Re-enable the ng resource (fix stale IntersectionFeasibilityFunction args), supply the ng extender value per arc, add ng_size + enable_ng_augmentation ctor params and build_ng_arcs. - New benchmark rcspp-vrp-benchmark-ng sweeping ng sizes, logging instance / configuration / timing at the start and end of each run. Test: - tests/rcspp/resource/test_ng_unreachable.hpp: pure-rcspp regression test (no Gurobi) using the exact VRP resource pack; asserts identical optimum and strictly fewer labels with the augmentation on, and a no-op when reachable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r tractability The ng benchmark hung on wider-TW Solomon instances (C102+): exact ng-route pricing is ~O(n^3) labels, so the first CG iteration explored millions of labels. This was confirmed in the pure-rcspp harness (1010/3390/8020/15900/28200 labels for n=10..30 -- a clean n^3 fit), not a logic bug. Changes: - Drop the separate zero-dual 'price_once' labeling (its best_cost was a stale +inf sentinel and its label count was unrepresentative). The label count now comes from the CG run itself: add SolveResult::num_extended_labels, accumulate it across pricing iterations into the new CGSolveResult::total_pricing_labels, and report it from a single cg_run(). - Add early-stopping caps to keep pricing tractable: num_labels_to_extend_by_node (--max-labels, default 100) and stop_after_X_solutions = 4 x cols_per_iter (the latter needs return_dominated_solutions=true to take effect). - Add a VRP::solve max_columns_per_iter cap: add only the K most-negative columns per CG iteration (default: add all). The benchmark exposes it as --cols K (default #demand customers). Pricing is then heuristic (the LP bound is an estimate, not exact), but baseline and augmented runs use identical caps so the comparison stays fair. The cap mechanics are validated in the pure-rcspp harness (a DISABLED diagnostic test); SolveResult::num_extended_labels is asserted to match the algorithm getter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR significantly extends the RCSPP/VRP stack with (1) an ng-route “unreachable-set” dominance augmentation (intended as pure acceleration), (2) new algorithm capabilities (A* dominance ordering, tabu-style heuristics), and (3) infrastructure for memory limiting/pressure pruning, plus updated benchmarks, tests, and Python bindings to exercise/consume these features.
Changes:
- Add memory-limit/pressure-pruning support to labeling algorithms (with new tests and Python exposure of memory queries).
- Add ng-route unreachable-set augmentation (composition-level extension hook + VRP integration + regression test + benchmark).
- Introduce additional algorithms and benchmarking support (A* dominance, tabu list/search variants, heterogeneous “extra solvers”, optional Boost build).
Reviewed changes
Copilot reviewed 63 out of 65 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/rcspp/vrp_subproblem/vrp_subproblem.hpp | Plumbs base params through test subproblem solve; adds ref-count consistency helper |
| tests/rcspp/test_rcspp.hpp | Adds A* tests + memory-limit and ref-count regression tests |
| tests/rcspp/test_main.cpp | Reorders/includes new test headers (ng unreachable) |
| tests/rcspp/test_label_buckets.hpp | Adds multi-bucket regression tests + suggest_range test |
| tests/rcspp/resource/test_ng_unreachable.hpp | New regression tests for ng unreachable augmentation |
| src/vrp/vrp.hpp | VRP API changes: CGSolveResult, ExtraSolver, optional Boost, ng augmentation wiring |
| src/vrp/vrp.cpp | Implements ng augmentation setup; makes Boost optional; Path uses vector |
| src/vrp/main.cpp | Makes Boost include conditional |
| src/vrp/CMakeLists.txt | Makes Boost optional; adds ng/large benchmarks; defines RCSPP_VRP_HAS_BOOST |
| src/vrp/cg/path.hpp | Path visited_nodes switched to std::vector |
| src/vrp/cg/path.cpp | Updates Path ctor for std::vector |
| src/vrp/benchmark_ng_main.cpp | New benchmark sweeping ng sizes & augmentation |
| src/vrp/benchmark_main.cpp | Benchmark refactor to new solve result + extra solvers |
| src/vrp/benchmark_large_main.cpp | New/updated large benchmark driver |
| src/vrp/benchmark_common.hpp | Shared benchmark table formatting + Solomon BKS data |
| src/rcspp/utils/memory.hpp | New cross-platform memory query + memory limit helper |
| src/rcspp/resource/resource_traits.hpp | Adds composition membership trait for cost type (A* heuristic) |
| src/rcspp/resource/resource_graph.hpp | Adds composition extension setter; solve() now returns SolveResult; base-params solve overload |
| src/rcspp/resource/concrete/numerical_resource.hpp | Adds leq overload with delta; signature cleanup |
| src/rcspp/resource/composition/functions/extension/ng_unreachable_composition_extension_function.hpp | New unreachable-set augmentation implementation |
| src/rcspp/resource/composition/functions/extension/composition_extension_function.hpp | Adds post_extend hooks for composition-level extension postprocessing |
| src/rcspp/resource/base/resource_factory.hpp | Allows replacing extension function before arc creation |
| src/rcspp/rcspp.hpp | Exposes new algorithms/utilities (A*, tabu, memory) in umbrella header |
| src/rcspp/preprocessor/connectivity_matrix.hpp | Includes in-arcs when building adjacency (SCC/connectivity) |
| src/rcspp/preprocessor/bellman_ford_algorithm.hpp | Refactors Bellman–Ford to share relaxation loop; adds overloads |
| src/rcspp/label/label.hpp | Adds prev_label/ref_count bookkeeping for path reconstruction & safe release |
| src/rcspp/label/label_pool.hpp | Adds ref-count-aware release + consistency check + pool release() |
| src/rcspp/label/label_factory.hpp | Initializes new label bookkeeping fields |
| src/rcspp/graph/graph.hpp | Adds mutable for_each_arc overload |
| src/rcspp/algorithm/tabu_search.hpp | New tabu-search constructive heuristic |
| src/rcspp/algorithm/tabu_list.hpp | New reusable tabu list utility |
| src/rcspp/algorithm/simple_dominance_algorithm.hpp | Ref-count-safe release + memory pressure pruning |
| src/rcspp/algorithm/pushing_dominance_algorithm.hpp | Memory pressure pruning + uses effective per-node cap |
| src/rcspp/algorithm/pulling_dominance_algorithm.hpp | Adds memory limit checks + ref-count-safe release + memory pressure pruning |
| src/rcspp/algorithm/improving_tabu_search.hpp | New improving tabu-search heuristic |
| src/rcspp/algorithm/greedy.hpp | Uses unified should_stop() termination |
| src/rcspp/algorithm/dominance_algorithm.hpp | Adds SolveResult integration, memory checks, prev_label path reconstruction |
| src/rcspp/algorithm/diversification_search.hpp | Refactors diversification to use TabuList + SolveResult |
| src/rcspp/algorithm/backtracking_dive_algorithm.hpp | New shared DFS/backtracking base for heuristics |
| src/rcspp/algorithm/astar_dominance_algorithm.hpp | New A* priority dominance algorithm + dispatch wrapper |
| src/rcspp/algorithm/algorithm.hpp | Introduces AlgorithmStatus/SolveResult + timeout/memory-limit plumbing |
| src/python/test_vrp.py | Fixes sys.path handling for test execution |
| src/python/test_rcspp.py | Updates examples for new algorithms and bucket params; path fixes |
| src/python/test_rcspp_networkx.py | Fixes sys.path handling |
| src/python/test_graph.py | Makes numpy optional via pytest.importorskip; path fixes |
| src/python/test_clone.py | Makes numpy optional via pytest.importorskip; naming/doc tweaks |
| src/python_interface/rcspp/solution_pool.cpp | Braces/formatting cleanup in predicate |
| src/python_interface/rcspp/rcspp.cpp | Exposes process/available memory helper functions |
| src/python_interface/rcspp/pricing_pool.py | Improves SharedMemory attach for Python 3.13+ (track=False) |
| src/python_interface/rcspp/graph.py | Adds Tabu/A* aliases; returns SolveResult; adds BucketAlgorithmParams wrapper |
| src/python_interface/rcspp/graph.cpp | Binds AlgorithmStatus/SolveResult + new params fields + new algorithms |
| src/python_interface/rcspp/graph_impl.hpp | Dispatch now returns SolveResult; adds A* dispatch; optimizes bulk row append |
| src/python_interface/rcspp/_core/resource.pyi | New typing stubs for resource function classes |
| src/python_interface/rcspp/_core/logger.pyi | New typing stubs for logger |
| src/python_interface/rcspp/_core/graph.pyi | New typing stubs for graph + SolveResult |
| src/python_interface/rcspp/_core/init.pyi | Exposes stub submodules |
| src/python_interface/rcspp/init.py | Exposes SolveResult/AlgorithmStatus + memory helpers in package API |
| src/python_interface/CMakeLists.txt | Installs .pyi and py.typed; copies stubs at build time |
| instances/RC201_12.txt | Adds new Git LFS pointer instance file |
| .pre-commit-config.yaml | Excludes build dirs from markdownlint |
| .gitignore | Expands ignored build/python/cache/IDE artifacts |
| .github/workflows/ci.yml | Adds python-version matrix; improves pytest output |
| .github/workflows/benchmark.yml | Adds manual benchmark workflow (small/large) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+130
to
+134
| AlgorithmParams<LabelList<ResourceType>> list_params; | ||
| auto [timers, lp_cost] = vrp.solve<SimpleDominanceAlgorithm, | ||
| PushingDominanceAlgorithm, | ||
| PullingDominanceAlgorithm>(list_params, | ||
| std::nullopt, |
Comment on lines
+182
to
+186
| std::string path = inst_dir + name + ".txt"; | ||
| LOG_INFO("Instance: ", path, '\n'); | ||
| auto [timers, lp_cost] = run_vrp(path, run_boost, run_astar); | ||
| if (total_timers.empty()) { | ||
| total_timers = timers; |
Comment on lines
+196
to
+200
| for (const auto& path : gh_instance_paths) { | ||
| std::string name = fs::path(path).stem().string(); | ||
| LOG_INFO("Instance: ", path, '\n'); | ||
| auto [timers, lp_cost] = run_vrp(path, run_boost, run_astar); | ||
| if (total_timers.empty()) { |
Comment on lines
+6
to
10
| #include <algorithm> | ||
| #include <cstddef> | ||
| #include <functional> | ||
| #include <limits> | ||
| #include <optional> |
| "\n"); | ||
| if (algo_index > first_rcspp_idx && !non_optimal && | ||
| !solutions_rcspp_any.empty()) { | ||
| double diff = abs(sols[0].cost - solutions_rcspp_any[0].cost); |
Comment on lines
+84
to
+88
| // Predecessor label set at extension time; valid as long as ref_count keeps it pinned. | ||
| 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
+14
to
+18
| #include <gtest/gtest.h> | ||
|
|
||
| #include <algorithm> | ||
| #include <cmath> | ||
| #include <limits> |
Comment on lines
+8
to
+14
| class Algorithm(Enum): | ||
| Simple: Algorithm | ||
| Pushing: Algorithm | ||
| Pulling: Algorithm | ||
| Greedy: Algorithm | ||
| Tabu: Algorithm | ||
|
|
…sult - Add <cstddef> to path.hpp for size_t - Add <memory> to master_problem.hpp for std::unique_ptr - Update structured bindings to include total_pricing_labels (3rd field) - Add --instance flag to benchmark_ng_main to run a single named instance Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parallelize the ng-route benchmark on SLURM with one job per (instance, ng-size) by default (or per (family, ng-size) with --group-by family). - scripts/gen_ng_jobs.py: generate a job manifest (one benchmark CLI line per job) for the sbatch array and print the matching --array range. - scripts/run_ng_benchmark.slurm: array runner; task N executes manifest line N+1 via rcspp-vrp-benchmark-ng (guards against missing manifest/binary and an out-of-range array index). - gitignore the generated manifest (scripts/ng_jobs.txt) and logs/. Relies on the benchmark's --instance / --family selectors (already added). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add t_base, t_aug and t_drop% columns to the ng benchmark summary table (mirroring nlab_base / nlab_aug / drop%): CgStats now carries the per-run wall-clock seconds, and t_drop% = 100*(t_base - t_aug)/t_base. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.