Skip to content

Fix #167: Add TravelingSalesman to QUBO reduction#605

Merged
GiggleLiu merged 7 commits intoCodingThrust:mainfrom
hmyuuu:issue-167-tsp-to-qubo
Mar 13, 2026
Merged

Fix #167: Add TravelingSalesman to QUBO reduction#605
GiggleLiu merged 7 commits intoCodingThrust:mainfrom
hmyuuu:issue-167-tsp-to-qubo

Conversation

@hmyuuu
Copy link
Contributor

@hmyuuu hmyuuu commented Mar 12, 2026

Summary

  • Add reduction from TravelingSalesman to QUBO using position-based encoding (Lucas 2014)
  • n² binary variables encode city-position assignments with one-hot row/column constraints
  • Supports non-complete graphs by penalizing non-edge consecutive pairs

Fixes #167

Co-authored with Claude (opus-4.6)

Co-authored-by: Claude <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.70%. Comparing base (d309549) to head (749f818).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #605      +/-   ##
==========================================
+ Coverage   96.61%   96.70%   +0.09%     
==========================================
  Files         218      220       +2     
  Lines       29352    29474     +122     
==========================================
+ Hits        28357    28503     +146     
+ Misses        995      971      -24     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

hmyuuu and others added 2 commits March 12, 2026 23:00
Position-based encoding (Lucas 2014): n² binary variables x_{v,p}
with one-hot row/column constraints and distance objective.
Handles non-complete graphs by penalizing non-edge consecutive pairs.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
@hmyuuu
Copy link
Contributor Author

hmyuuu commented Mar 12, 2026

Implementation Summary

Changes

  • src/rules/travelingsalesman_qubo.rs — Reduction rule using position-based encoding (Lucas 2014). n² QUBO variables with one-hot row/column constraints (H_A, H_B) and distance objective (H_C). Handles non-complete graphs by penalizing non-edge consecutive pairs with penalty A.
  • src/rules/mod.rs — Module registration
  • src/unit_tests/rules/travelingsalesman_qubo.rs — 3 tests: closed-loop on K3 (cost 6), K4 unit weights (cost 4), and size verification (n²)
  • examples/reduction_travelingsalesman_to_qubo.rs — K3 example with weights [1,2,3], cross-checked against brute force
  • tests/suites/examples.rs — Example test registration
  • docs/paper/examples/travelingsalesman_to_qubo{,.result}.json — Generated example data

Deviations from Plan

  • None

Open Questions

  • None

Co-authored with Claude (opus-4.6)

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

Adds a new reduction from TravelingSalesman<SimpleGraph, i32> to QUBO<f64>, along with an executable example and tests, and wires the example into the integration test suite.

Changes:

  • Implement TravelingSalesman -> QUBO reduction using position-based (n²) binary encoding with penalty constraints.
  • Add unit tests validating closed-loop optimality and basic size expectations for the new reduction.
  • Add a runnable example and generated docs JSON outputs; include the example in tests/suites/examples.rs.

Reviewed changes

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

Show a summary per file
File Description
tests/suites/examples.rs Adds the new TSP→QUBO example module and corresponding test invocation.
src/unit_tests/rules/travelingsalesman_qubo.rs Introduces unit tests for correctness and sizing of the reduction.
src/rules/travelingsalesman_qubo.rs Implements the new reduction and solution extraction logic.
src/rules/mod.rs Registers the new reduction module for compilation/registration.
examples/reduction_travelingsalesman_to_qubo.rs New example demonstrating reduction, solving, extraction, and export.
docs/paper/examples/travelingsalesman_to_qubo.json Adds exported reduction structure JSON for the paper docs.
docs/paper/examples/travelingsalesman_to_qubo.result.json Adds exported solution pairs JSON for the paper docs.

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

Comment on lines +78 to +95
// Build edge weight map (both directions for undirected lookup)
let mut edge_weight_map: HashMap<(usize, usize), f64> = HashMap::new();
for (u, v, w) in self.edges() {
let wf = w as f64;
edge_weight_map.insert((u, v), wf);
edge_weight_map.insert((v, u), wf);
}

// Build edge index map: canonical (min, max) → edge index
let mut edge_index: HashMap<(usize, usize), usize> = HashMap::new();
for (idx, &(u, v)) in graph_edges.iter().enumerate() {
edge_index.insert((u.min(v), u.max(v)), idx);
}

// Penalty weight: must exceed any possible tour cost
let weight_sum: f64 = self.edges().iter().map(|(_, _, w)| (*w as f64).abs()).sum();
let a = 1.0 + weight_sum;

Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

reduce_to() calls self.edges() multiple times (once to build edge_weight_map, again to compute weight_sum). TravelingSalesman::edges() allocates a new Vec each call, so this adds avoidable allocations/cloning. Consider calling self.edges() once and reusing the collected edges/weights for both the map and the penalty computation (or otherwise compute weight_sum while building the map).

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +23
pub struct ReductionTravelingSalesmanToQUBO {
target: QUBO<f64>,
num_vertices: usize,
edges: Vec<(usize, usize)>,
edge_index: HashMap<(usize, usize), usize>,
}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

ReductionTravelingSalesmanToQUBO stores edges: Vec<(usize, usize)>, but it’s only used for self.edges.len() when sizing the extracted source config. This keeps an extra copy of the graph’s edge list alive for the lifetime of the reduction result. Consider storing just num_edges (or deriving the length from edge_index.len()) instead of storing the full edges vector.

Copilot uses AI. Check for mistakes.
hmyuuu and others added 4 commits March 13, 2026 01:20
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
…all self.edges() once

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@GiggleLiu
Copy link
Contributor

Review Pipeline Report

Check Result
Copilot comments 2 fixed (store num_edges instead of edges Vec; call self.edges() once)
Merge with main clean merge, pushed
Issue/human comments 3 checked, 0 actionable (quality-check reports + implementation summary)
CI green (Test, Clippy, Coverage, Codecov all pass)
Agentic test passed (K3, K4, K5 instances all produce correct optimal tours)
Board review-agentic → In Review

🤖 Generated by review-pipeline

@GiggleLiu GiggleLiu merged commit 63bbdf9 into CodingThrust:main Mar 13, 2026
5 checks passed
@hmyuuu hmyuuu deleted the issue-167-tsp-to-qubo branch March 13, 2026 11:41
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.

[Rule] TravelingSalesman to QUBO

3 participants