The problem
What changes when you solve the same problem in a different language? Polyglot-TSP uses brute-force Traveling Salesman solutions across more than 50 languages to compare implementation choices, runtime behavior, and the cost of factorial growth.
The approach: Each implementation solves the same routing problem. Comparing the code and benchmark results exposes differences in allocation, representation, and execution.
Reported project measurements: 100% baseline output verification across 50+ language implementations; sub-microsecond execution on native Rust/C++ implementations; automated multi-target CI matrix.
How it works
Unified Test Harness & Process Driver: scripts/run_all.py maps file extensions to compiler flags, abstracting invocation models across native executables, bytecode interpreters, and JVM/CLR/Wasm targets.
Canonical Baseline Verification: All implementations execute identical TSP adjacency matrices (Distance 60, 80, 97) and emit standardized JSON/stdout tuples (min_distance, best_route) verified by a central test suite.
Cross-Paradigm Idiomatic Fidelity: Each language implements the algorithm using idiomatic paradigms (e.g. Heap's algorithm in Rust, lazy stream permutations in Haskell, finite state machines in Verilog).
How the pieces connect
flowchart TD
A[Test Matrix Dataset: test_cases.json] --> B[Testing Orchestrator: scripts/run_all.py]
B --> C[Systems & Compiled: C, C++, Rust, Zig, D, Go, Ada/SPARK]
B --> D[Functional & Declarative: Haskell, OCaml, Scheme, Clojure, Erlang]
B --> E[Array & Dynamic: APL, BQN, J, Python, Ruby, Julia, Lua]
B --> F[Hardware & HDL: VHDL, Verilog]
B --> G[Legacy & Esoteric: COBOL, Fortran, Modula-2, INTERCAL]
C & D & E & F & G --> H[Canonical Distance & Route Parser]
H --> I[Standardized Verification: Distance 60 / 80 / 97]
Implementation notes
Rust: Zero-Cost Abstractions & Memory Safety (languages/rust/tsp.rs)
pub fn solve_tsp(matrix: &[Vec]) -> (u32, Vec) {
let n = matrix.len();
let mut cities: Vec = (1..n).collect();
let mut min_cost = u32::MAX;
let mut best_route = Vec::new();
let mut permutations = Vec::new();
heap_permute(&mut cities, n - 1, &mut permutations);
for perm in permutations {
let mut current_cost = matrix[0][perm[0]];
for i in 0..perm.len() - 1 {
current_cost += matrix[perm[i]][perm[i + 1]];
}
current_cost += matrix[perm[perm.len() - 1]][0];
if current_cost < min_cost {
min_cost = current_cost;
let mut full_route = vec![0];
full_route.extend_from_slice(&perm);
full_route.push(0);
best_route = full_route;
}
}
(min_cost, best_route)
}
Haskell: Lazy Stream Recursion (languages/haskell/TSP.hs)
module TSP (solveTSP) where
import Data.List (permutations)
solveTSP :: [[Int]] -> (Int, [Int])
solveTSP matrix =
let n = length matrix
cityIndices = [1 .. n - 1]
allRoutes = [0 : p ++ [0] | p <- permutations cityIndices]
routeCost r = sum $ zipWith (\a b -> (matrix !! a) !! b) r (tail r)
costs = map (\r -> (routeCost r, r)) allRoutes
in foldl1 (\acc@(c1, _) item@(c2, _) -> if c2 < c1 then item else acc) costs
Tradeoffs and lessons
- Process-Level Assertion vs. C-ABI FFI: Chose process stdout stream assertion over C-ABI bindings to accommodate esoteric and simulated runtimes (INTERCAL, Verilog HDL) without linking incompatibilities.
- Brute-Force Permutations ($O(N!)$) Parity: Maintained identical brute-force algorithms across all languages rather than heuristics to isolate raw language runtime efficiency.