Imports
Structural properties of the canonical TSP matrix order
namespace CLRS.Chapter34The TSP matrix and graph-complement developments use the same canonical strict-pair order.
theorem tspNormalizedPairs_eq_vertexCoverNormalizedPairs (n : Nat) :
tspNormalizedPairs n = vertexCoverNormalizedPairs n := by
induction n with
| zero => rfl
| succ n ih =>
simp only [tspNormalizedPairs, vertexCoverNormalizedPairs, ih]
theorem tspNormalizedPairs_nodup (n : Nat) :
(tspNormalizedPairs n).Nodup := by
induction n with
| zero => simp [tspNormalizedPairs]
| succ n ih =>
rw [tspNormalizedPairs, List.nodup_append']
refine ⟨ih, ?_, ?_⟩
· exact (List.nodup_range.map fun left right heq => by
simpa using congrArg Prod.fst heq)
· rw [List.disjoint_left]
intro pair hprior hnew
have hpriorBounds := mem_tspNormalizedPairs_iff.mp hprior
rcases List.mem_map.mp hnew with ⟨lower, hlower, heq⟩
have hsecond := congrArg Prod.snd heq
simp only at hsecond
omegatheorem tspPairOrientations_nodup {pair : Nat × Nat}
(hlt : pair.1 < pair.2) :
(tspPairOrientations pair).Nodup := by
rcases pair with ⟨u, v⟩
simp [tspPairOrientations, Prod.ext_iff]
omega
private theorem tspPairOrientations_disjoint
{left right : Nat × Nat}
(hleft : left.1 < left.2) (hright : right.1 < right.2)
(hne : left ≠ right) :
List.Disjoint (tspPairOrientations left) (tspPairOrientations right) := by
rw [List.disjoint_left]
intro pair hpairLeft hpairRight
simp only [tspPairOrientations, List.mem_cons, List.not_mem_nil,
or_false] at hpairLeft hpairRight
rcases hpairLeft with hforward | hreverse <;>
rcases hpairRight with hforward' | hreverse'
· exact hne (hforward.symm.trans hforward')
· have heq := hforward.symm.trans hreverse'
have hfirst := congrArg Prod.fst heq
have hsecond := congrArg Prod.snd heq
simp only at hfirst hsecond
omega
· have heq := hreverse.symm.trans hforward'
have hfirst := congrArg Prod.fst heq
have hsecond := congrArg Prod.snd heq
simp only at hfirst hsecond
omega
· have heq := hreverse.symm.trans hreverse'
apply hne
exact Prod.ext (congrArg Prod.snd heq) (congrArg Prod.fst heq)
theorem tspOrientations_nodup (n : Nat) :
((tspNormalizedPairs n).flatMap tspPairOrientations).Nodup := by
rw [List.nodup_flatMap]
refine ⟨?_, ?_⟩
· intro pair hpair
exact tspPairOrientations_nodup
(mem_tspNormalizedPairs_iff.mp hpair).1
· exact (tspNormalizedPairs_nodup n).imp_of_mem (by
intro left right hleft hright hne
exact tspPairOrientations_disjoint
(mem_tspNormalizedPairs_iff.mp hleft).1
(mem_tspNormalizedPairs_iff.mp hright).1 hne)The physical complete-matrix order contains every directed pair exactly once.
theorem tspPairOrder_nodup (n : Nat) : (tspPairOrder n).Nodup := by
rw [tspPairOrder, List.nodup_append']
refine ⟨?_, tspOrientations_nodup n, ?_⟩
· exact (List.nodup_range.map fun left right heq => by
simpa using congrArg Prod.fst heq)
· rw [List.disjoint_left]
intro pair hdiagonal horientation
rcases List.mem_map.mp hdiagonal with ⟨vertex, hvertex, rfl⟩
rcases List.mem_flatMap.mp horientation with
⟨normalized, hnormalized, horientation⟩
have hlt := (mem_tspNormalizedPairs_iff.mp hnormalized).1
rcases normalized with ⟨u, v⟩
simp [tspPairOrientations, Prod.ext_iff] at horientation
rcases horientation with heq | heq <;> omegaAligned lookup followed over the same duplicate-free key list recovers the entire value stream.
theorem map_lookupTSPWeight_eq (pairs : List (Nat × Nat))
(weights : List Nat) (hnodup : pairs.Nodup)
(hlength : weights.length = pairs.length) :
pairs.map (fun pair =>
lookupTSPWeight pairs weights pair.1 pair.2) = weights := by
induction pairs generalizing weights with
| nil =>
cases weights with
| nil => rfl
| cons weight weights => simp at hlength
| cons pair pairs ih =>
cases weights with
| nil => simp at hlength
| cons weight weights =>
simp only [List.nodup_cons] at hnodup
simp only [List.length_cons, Nat.succ.injEq] at hlength
rw [List.map_cons]
simp only [lookupTSPWeight, ↓reduceIte]
apply congrArg (weight :: ·)
calc
pairs.map (fun next =>
lookupTSPWeight (pair :: pairs) (weight :: weights)
next.1 next.2) =
pairs.map (fun next =>
lookupTSPWeight pairs weights next.1 next.2) := by
apply List.map_congr_left
intro next hnext
simp only [lookupTSPWeight]
rw [if_neg]
intro heq
exact hnodup.1 (heq ▸ hnext)
_ = weights := ih weights hnodup.2 hlength
Every well-sized raw matrix is its canonical key order mapped through the
lookup operation used by TSPData.toInstance.
theorem tspWeights_eq_map_lookup (data : TSPData)
(hshape : data.weights.length = data.vertexCount * data.vertexCount) :
data.weights =
(tspPairOrder data.vertexCount).map fun pair =>
lookupTSPWeight (tspPairOrder data.vertexCount) data.weights
pair.1 pair.2 := by
symm
apply map_lookupTSPWeight_eq
· exact tspPairOrder_nodup _
· simpa using hshapeend CLRS.Chapter34