Theory Floyd_Warshall
theory Floyd_Warshall
imports Main
begin
chapter ‹Floyd-Warshall Algorithm for the All-Pairs Shortest Paths Problem›
subsubsection ‹Auxiliary›
lemma distinct_list_single_elem_decomp: "{xs. set xs ⊆ {0} ∧ distinct xs} = {[], [0]}"
proof (standard, goal_cases)
case 1
{ fix xs :: "'a list" assume xs: "xs ∈ {xs. set xs ⊆ {0} ∧ distinct xs}"
have "xs ∈ {[], [0]}"
proof (cases xs)
case (Cons y ys)
hence y: "y = 0" using xs by auto
with Cons xs have "ys = []" by (cases ys, auto)
thus ?thesis using y Cons by simp
qed simp
}
thus ?case by blast
qed simp
section ‹Cycles in Lists›
abbreviation "cnt x xs ≡ length (filter (λy. x = y) xs)"
fun remove_cycles :: "'a list ⇒ 'a ⇒ 'a list ⇒ 'a list"
where
"remove_cycles [] _ acc = rev acc" |
"remove_cycles (x#xs) y acc =
(if x = y then remove_cycles xs y [x] else remove_cycles xs y (x#acc))"
lemma cnt_rev: "cnt x (rev xs) = cnt x xs" by (metis length_rev rev_filter)
value "as @ [x] @ bs @ [x] @ cs @ [x] @ ds"
lemma remove_cycles_removes: "cnt x (remove_cycles xs x ys) ≤ max 1 (cnt x ys)"
proof (induction xs arbitrary: ys)
case Nil thus ?case
by (simp, cases "x ∈ set ys", (auto simp: cnt_rev[of x ys]))
next
case (Cons y xs)
thus ?case
proof (cases "x = y")
case True
thus ?thesis using Cons[of "[y]"] True by auto
next
case False
thus ?thesis using Cons[of "y # ys"] by auto
qed
qed
lemma remove_cycles_id: "x ∉ set xs ⟹ remove_cycles xs x ys = rev ys @ xs"
by (induction xs arbitrary: ys) auto
lemma remove_cycles_cnt_id:
"x ≠ y ⟹ cnt y (remove_cycles xs x ys) ≤ cnt y ys + cnt y xs"
proof (induction xs arbitrary: ys x)
case Nil thus ?case by (simp add: cnt_rev)
next
case (Cons z xs)
thus ?case
proof (cases "x = z")
case True thus ?thesis using Cons.IH[of z "[z]"] Cons.prems by auto
next
case False
thus ?thesis using Cons.IH[of x "z # ys"] Cons.prems False by auto
qed
qed
lemma remove_cycles_ends_cycle: "remove_cycles xs x ys ≠ rev ys @ xs ⟹ x ∈ set xs"
using remove_cycles_id by fastforce
lemma remove_cycles_begins_with: "x ∈ set xs ⟹ ∃ zs. remove_cycles xs x ys = x # zs ∧ x ∉ set zs"
proof (induction xs arbitrary: ys)
case Nil thus ?case by auto
next
case (Cons y xs)
thus ?case
proof (cases "x = y")
case True thus ?thesis
proof (cases "x ∈ set xs", goal_cases)
case 1 with Cons show ?case by auto
next
case 2 with remove_cycles_id[of x xs "[y]"] show ?case by auto
qed
next
case False
with Cons show ?thesis by auto
qed
qed
lemma remove_cycles_self:
"x ∈ set xs ⟹ remove_cycles (remove_cycles xs x ys) x zs = remove_cycles xs x ys"
proof -
assume x:"x ∈ set xs"
then obtain ws where ws: "remove_cycles xs x ys = x # ws" "x ∉ set ws"
using remove_cycles_begins_with[OF x, of ys] by blast
from remove_cycles_id[OF this(2)] have "remove_cycles ws x [x] = x # ws" by auto
with ws(1) show "remove_cycles (remove_cycles xs x ys) x zs = remove_cycles xs x ys" by simp
qed
lemma remove_cycles_one: "remove_cycles (as @ x # xs) x ys = remove_cycles (x#xs) x ys"
by (induction as arbitrary: ys) auto
lemma remove_cycles_cycles:
"x ∈ set xs ⟹ ∃ xxs as. as @ concat (map (λ xs. x # xs) xxs) @ remove_cycles xs x ys = xs ∧ x ∉ set as"
proof (induction xs arbitrary: ys)
case Nil thus ?case by auto
next
case (Cons y xs)
thus ?case
proof (cases "x = y")
case True thus ?thesis
proof (cases "x ∈ set xs", goal_cases)
case 1
then obtain as xxs where "as @ concat (map (λxs. y#xs) xxs) @ remove_cycles xs y [y] = xs"
using Cons.IH[of "[y]"] by auto
hence "[] @ concat (map (λxs. x#xs) (as#xxs)) @ remove_cycles (y#xs) x ys = y # xs"
by (simp add: ‹x = y›)
thus ?thesis by fastforce
next
case 2
hence "remove_cycles (y # xs) x ys = y # xs" using remove_cycles_id[of x xs "[y]"] by auto
hence "[] @ concat (map (λxs. x # xs) []) @ remove_cycles (y#xs) x ys = y # xs" by auto
thus ?thesis by fastforce
qed
next
case False
then obtain as xxs where as:
"as @ concat (map (λxs. x # xs) xxs) @ remove_cycles xs x (y#ys) = xs" "x ∉ set as"
using Cons.IH[of "y # ys"] Cons.prems by auto
hence "(y # as) @ concat (map (λxs. x # xs) xxs) @ remove_cycles (y#xs) x ys = y # xs"
using ‹x ≠ y› by auto
thus ?thesis using as(2) ‹x ≠ y› by fastforce
qed
qed
fun start_remove :: "'a list ⇒ 'a ⇒ 'a list ⇒ 'a list"
where
"start_remove [] _ acc = rev acc" |
"start_remove (x#xs) y acc =
(if x = y then rev acc @ remove_cycles xs y [y] else start_remove xs y (x # acc))"
lemma start_remove_decomp:
"x ∈ set xs ⟹ ∃ as bs. xs = as @ x # bs ∧ start_remove xs x ys = rev ys @ as @ remove_cycles bs x [x]"
proof (induction xs arbitrary: ys)
case Nil thus ?case by auto
next
case (Cons y xs)
thus ?case
proof (auto, goal_cases)
case 1
from 1(1)[of "y # ys"]
obtain as bs where
"xs = as @ x # bs" "start_remove xs x (y # ys) = rev (y # ys) @ as @ remove_cycles bs x [x]"
by blast
hence "y # xs = (y # as) @ x # bs"
"start_remove xs x (y # ys) = rev ys @ (y # as) @ remove_cycles bs x [x]" by simp+
thus ?case by blast
qed
qed
lemma start_remove_removes: "cnt x (start_remove xs x ys) ≤ Suc (cnt x ys)"
proof (induction xs arbitrary: ys)
case Nil thus ?case using cnt_rev[of x ys] by auto
next
case (Cons y xs)
thus ?case
proof (cases "x = y")
case True
thus ?thesis using remove_cycles_removes[of y xs "[y]"] cnt_rev[of y ys] by auto
next
case False
thus ?thesis using Cons[of "y # ys"] by auto
qed
qed
lemma start_remove_id[simp]: "x ∉ set xs ⟹ start_remove xs x ys = rev ys @ xs"
by (induction xs arbitrary: ys) auto
lemma start_remove_cnt_id:
"x ≠ y ⟹ cnt y (start_remove xs x ys) ≤ cnt y ys + cnt y xs"
proof (induction xs arbitrary: ys)
case Nil thus ?case by (simp add: cnt_rev)
next
case (Cons z xs)
thus ?case
proof (cases "x = z", goal_cases)
case 1 thus ?case using remove_cycles_cnt_id[of x y xs "[x]"] by (simp add: cnt_rev)
next
case 2 from this(1)[of "(z # ys)"] this(2,3) show ?case by auto
qed
qed
fun remove_all_cycles :: "'a list ⇒ 'a list ⇒ 'a list"
where
"remove_all_cycles [] xs = xs" |
"remove_all_cycles (x # xs) ys = remove_all_cycles xs (start_remove ys x [])"
lemma cnt_remove_all_mono:"cnt y (remove_all_cycles xs ys) ≤ max 1 (cnt y ys)"
proof (induction xs arbitrary: ys)
case Nil thus ?case by auto
next
case (Cons x xs)
thus ?case
proof (cases "x = y")
case True thus ?thesis using start_remove_removes[of y ys "[]"] Cons[of "start_remove ys y []"]
by auto
next
case False
hence "cnt y (start_remove ys x []) ≤ cnt y ys"
using start_remove_cnt_id[of x y ys "[]"] by auto
thus ?thesis using Cons[of "start_remove ys x []"] by auto
qed
qed
lemma cnt_remove_all_cycles: "x ∈ set xs ⟹ cnt x (remove_all_cycles xs ys) ≤ 1"
proof (induction xs arbitrary: ys)
case Nil thus ?case by auto
next
case (Cons y xs)
thus ?case
using start_remove_removes[of x ys "[]"] cnt_remove_all_mono[of y xs "start_remove ys y []"]
by auto
qed
lemma cnt_mono:
"cnt a (b # xs) ≤ cnt a (b # c # xs)"
by (induction xs) auto
lemma cnt_distinct_intro: "∀ x ∈ set xs. cnt x xs ≤ 1 ⟹ distinct xs"
proof (induction xs)
case Nil thus ?case by auto
next
case (Cons x xs)
from this(2) have "∀ x ∈ set xs. cnt x xs ≤ 1"
by (metis filter.simps(2) impossible_Cons linorder_class.linear list.set_intros(2)
preorder_class.order_trans)
with Cons.IH have "distinct xs" by auto
moreover have "x ∉ set xs" using Cons.prems
proof (induction xs)
case Nil then show ?case by auto
next
case (Cons a xs)
from this(2) have "∀xa∈set (x # xs). cnt xa (x # a # xs) ≤ 1"
by auto
then have *: "∀xa∈set (x # xs). cnt xa (x # xs) ≤ 1"
proof (safe, goal_cases)
case (1 b)
then have "cnt b (x # a # xs) ≤ 1" by auto
with cnt_mono[of b x xs a] show ?case by fastforce
qed
with Cons(1) have "x ∉ set xs" by auto
moreover have "x ≠ a"
by (metis (full_types) Cons.prems One_nat_def * empty_iff filter.simps(2) impossible_Cons
le_0_eq le_Suc_eq length_0_conv list.set(1) list.set_intros(1))
ultimately show ?case by auto
qed
ultimately show ?case by auto
qed
lemma remove_cycles_subs:
"set (remove_cycles xs x ys) ⊆ set xs ∪ set ys"
by (induction xs arbitrary: ys; auto; fastforce)
lemma start_remove_subs:
"set (start_remove xs x ys) ⊆ set xs ∪ set ys"
using remove_cycles_subs by (induction xs arbitrary: ys; auto; fastforce)
lemma remove_all_cycles_subs:
"set (remove_all_cycles xs ys) ⊆ set ys"
using start_remove_subs by (induction xs arbitrary: ys, auto) (fastforce+)
lemma remove_all_cycles_distinct: "set ys ⊆ set xs ⟹ distinct (remove_all_cycles xs ys)"
proof -
assume "set ys ⊆ set xs"
hence "∀ x ∈ set ys. cnt x (remove_all_cycles xs ys) ≤ 1" using cnt_remove_all_cycles by fastforce
hence "∀ x ∈ set (remove_all_cycles xs ys). cnt x (remove_all_cycles xs ys) ≤ 1"
using remove_all_cycles_subs by fastforce
thus "distinct (remove_all_cycles xs ys)" using cnt_distinct_intro by auto
qed
lemma distinct_remove_cycles_inv: "distinct (xs @ ys) ⟹ distinct (remove_cycles xs x ys)"
proof (induction xs arbitrary: ys)
case Nil thus ?case by auto
next
case (Cons y xs)
thus ?case by auto
qed
definition "remove_all x xs = (if x ∈ set xs then tl (remove_cycles xs x []) else xs)"
definition "remove_all_rev x xs = (if x ∈ set xs then rev (tl (remove_cycles (rev xs) x [])) else xs)"
lemma remove_all_distinct:
"distinct xs ⟹ distinct (x # remove_all x xs)"
proof (cases "x ∈ set xs", goal_cases)
case 1
from remove_cycles_begins_with[OF 1(2), of "[]"] obtain zs
where "remove_cycles xs x [] = x # zs" "x ∉ set zs" by auto
thus ?thesis using 1(1) distinct_remove_cycles_inv[of "xs" "[]" x] by (simp add: remove_all_def)
next
case 2 thus ?thesis by (simp add: remove_all_def)
qed
lemma remove_all_removes:
"x ∉ set (remove_all x xs)"
by (metis list.sel(3) remove_all_def remove_cycles_begins_with)
lemma remove_all_subs:
"set (remove_all x xs) ⊆ set xs"
using remove_cycles_subs remove_all_def
by (metis (no_types, lifting) append_Nil2 list.sel(2) list.set_sel(2) set_append subsetCE subsetI)
lemma remove_all_rev_distinct: "distinct xs ⟹ distinct (x # remove_all_rev x xs)"
proof (cases "x ∈ set xs", goal_cases)
case 1
then have "x ∈ set (rev xs)" by auto
from remove_cycles_begins_with[OF this, of "[]"] obtain zs
where "remove_cycles (rev xs) x [] = x # zs" "x ∉ set zs" by auto
thus ?thesis using 1(1) distinct_remove_cycles_inv[of "rev xs" "[]" x] by (simp add: remove_all_rev_def)
next
case 2 thus ?thesis by (simp add: remove_all_rev_def)
qed
lemma remove_all_rev_removes: "x ∉ set (remove_all_rev x xs)"
by (metis remove_all_def remove_all_removes remove_all_rev_def set_rev)
lemma remove_all_rev_subs: "set (remove_all_rev x xs) ⊆ set xs"
by (metis remove_all_def remove_all_subs set_rev remove_all_rev_def)
abbreviation "rem_cycles i j xs ≡ remove_all i (remove_all_rev j (remove_all_cycles xs xs))"
lemma rem_cycles_distinct': "i ≠ j ⟹ distinct (i # j # rem_cycles i j xs)"
proof -
assume "i ≠ j"
have "distinct (remove_all_cycles xs xs)" by (simp add: remove_all_cycles_distinct)
from remove_all_rev_distinct[OF this] have
"distinct (remove_all_rev j (remove_all_cycles xs xs))"
by simp
from remove_all_distinct[OF this] have "distinct (i # rem_cycles i j xs)" by simp
moreover have
"j ∉ set (rem_cycles i j xs)"
using remove_all_subs remove_all_rev_removes remove_all_removes by fastforce
ultimately show ?thesis by (simp add: ‹i ≠ j›)
qed
lemma rem_cycles_removes_last: "j ∉ set (rem_cycles i j xs)"
by (meson remove_all_rev_removes remove_all_subs rev_subsetD)
lemma rem_cycles_distinct: "distinct (rem_cycles i j xs)"
by (meson distinct.simps(2) order_refl remove_all_cycles_distinct
remove_all_distinct remove_all_rev_distinct)
lemma rem_cycles_subs: "set (rem_cycles i j xs) ⊆ set xs"
by (meson order_trans remove_all_cycles_subs remove_all_subs remove_all_rev_subs)
section ‹Definition of the Algorithm›
text ‹
We formalize the Floyd-Warshall algorithm on a linearly ordered abelian semigroup.
However, we would not need an ‹abelian› monoid if we had the right type class.
›
class linordered_ab_monoid_add = linordered_ab_semigroup_add +
fixes neutral :: 'a ("𝟭")
assumes neutl[simp]: "𝟭 + x = x"
assumes neutr[simp]: "x + 𝟭 = x"
begin
lemmas assoc = add.assoc
type_synonym 'c mat = "nat ⇒ nat ⇒ 'c"
definition (in -) upd :: "'c mat ⇒ nat ⇒ nat ⇒ 'c ⇒ 'c mat"
where
"upd m x y v = m (x := (m x) (y := v))"
definition fw_upd :: "'a mat ⇒ nat ⇒ nat ⇒ nat ⇒ 'a mat" where
"fw_upd m k i j ≡ upd m i j (min (m i j) (m i k + m k j))"
lemma fw_upd_mono:
"fw_upd m k i j i' j' ≤ m i' j'"
by (cases "i = i'", cases "j = j'") (auto simp: fw_upd_def upd_def)
fun fw :: "'a mat ⇒ nat ⇒ nat ⇒ nat ⇒ nat ⇒ 'a mat" where
"fw m n 0 0 0 = fw_upd m 0 0 0" |
"fw m n (Suc k) 0 0 = fw_upd (fw m n k n n) (Suc k) 0 0" |
"fw m n k (Suc i) 0 = fw_upd (fw m n k i n) k (Suc i) 0" |
"fw m n k i (Suc j) = fw_upd (fw m n k i j) k i (Suc j)"
lemma fw_invariant_aux_1:
"j'' ≤ j ⟹ i ≤ n ⟹ j ≤ n ⟹ k ≤ n ⟹ fw m n k i j i' j' ≤ fw m n k i j'' i' j'"
proof (induction j)
case 0 thus ?case by simp
next
case (Suc j) thus ?case
proof (cases "j'' = Suc j")
case True thus ?thesis by simp
next
case False
have "fw_upd (fw m n k i j) k i (Suc j) i' j' ≤ fw m n k i j i' j'" by (simp add: fw_upd_mono)
thus ?thesis using Suc False by simp
qed
qed
lemma fw_invariant_aux_2:
"i ≤ n ⟹ j ≤ n ⟹ k ≤ n ⟹ i'' ≤ i ⟹ j'' ≤ j
⟹ fw m n k i j i' j' ≤ fw m n k i'' j'' i' j'"
proof (induction i)
case 0 thus ?case using fw_invariant_aux_1 by auto
next
case (Suc i) thus ?case
proof (cases "i'' = Suc i")
case True thus ?thesis using Suc fw_invariant_aux_1 by simp
next
case False
have "fw m n k (Suc i) j i' j' ≤ fw m n k (Suc i) 0 i' j'"
using fw_invariant_aux_1[of 0 j "Suc i" n k] Suc(2-) by simp
also have "… ≤ fw m n k i n i' j'" by (simp add: fw_upd_mono)
also have "… ≤ fw m n k i j i' j'" using fw_invariant_aux_1[of j n i n k] False Suc by simp
also have "… ≤ fw m n k i'' j'' i' j'" using Suc False by simp
finally show ?thesis by simp
qed
qed
lemma fw_invariant:
"k' ≤ k ⟹ i ≤ n ⟹ j ≤ n ⟹ k ≤ n ⟹ j'' ≤ j ⟹ i'' ≤ i
⟹ fw m n k i j i' j' ≤ fw m n k' i'' j'' i' j'"
proof (induction k)
case 0 thus ?case using fw_invariant_aux_2 by auto
next
case (Suc k) thus ?case
proof (cases "k' = Suc k")
case True thus ?thesis using Suc fw_invariant_aux_2 by simp
next
case False
have "fw m n (Suc k) i j i' j' ≤ fw m n (Suc k) 0 0 i' j'"
using fw_invariant_aux_2[of i n j "Suc k" 0 0] Suc(2-) by simp
also have "… ≤ fw m n k n n i' j'" by (simp add: fw_upd_mono)
also have "… ≤ fw m n k i j i' j'" using fw_invariant_aux_2[of n n n k] False Suc by simp
also have "… ≤ fw m n k' i'' j'' i' j'" using Suc False by simp
finally show ?thesis by simp
qed
qed
lemma single_row_inv:
"j' < j ⟹ j ≤ n ⟹ i' ≤ n ⟹ fw m n k i' j i' j' = fw m n k i' j' i' j'"
proof (induction j)
case 0 thus ?case by simp
next
case (Suc j) thus ?case by (cases "j' = j") (simp add: fw_upd_def upd_def)+
qed
lemma single_iteration_inv':
"i' < i ⟹ j' ≤ n ⟹ j ≤ n ⟹ i ≤ n ⟹ fw m n k i j i' j' = fw m n k i' j' i' j'"
proof (induction i arbitrary: j)
case 0 thus ?case by simp
next
case (Suc i) thus ?case
proof (induction j)
case 0 thus ?case
proof (cases "i = i'", goal_cases)
case 2 thus ?case by (simp add: fw_upd_def upd_def)
next
case 1 thus ?case using single_row_inv[of j' n n i' m k]
by (cases "j' = n") (fastforce simp add: fw_upd_def upd_def)+
qed
next
case (Suc j) thus ?case by (simp add: fw_upd_def upd_def)
qed
qed
lemma single_iteration_inv:
"i' ≤ i ⟹ j' ≤ j ⟹ i ≤ n ⟹ j ≤ n⟹ fw m n k i j i' j' = fw m n k i' j' i' j'"
proof (induction i arbitrary: j)
case 0 thus ?case
proof (induction j)
case 0 thus ?case by simp
next
case (Suc j) thus ?case using 0 by (cases "j' = Suc j") (simp add: fw_upd_def upd_def)+
qed
next
case (Suc i) thus ?case
proof (induction j)
case 0 thus ?case by (cases "i' = Suc i") (simp add: fw_upd_def upd_def)+
next
case (Suc j) thus ?case
proof (cases "i' = Suc i", goal_cases)
case 1 thus ?case
proof (cases "j' = Suc j", goal_cases)
case 1 thus ?case by simp
next
case 2 thus ?case by (simp add: fw_upd_def upd_def)
qed
next
case 2 thus ?case
proof (cases "j' = Suc j", goal_cases)
case 1 thus ?case using single_iteration_inv'[of i' "Suc i" j' n "Suc j" m k] by simp
next
case 2 thus ?case by (simp add: fw_upd_def upd_def)
qed
qed
qed
qed
lemma fw_innermost_id:
"i ≤ n ⟹ j ≤ n ⟹ j' ≤ n ⟹ i' < i ⟹ fw m n 0 i' j' i j = m i j"
proof (induction i' arbitrary: j')
case 0 thus ?case
proof (induction j')
case 0 thus ?case by (simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp: fw_upd_def upd_def)
qed
next
case (Suc i') thus ?case
proof (induction j')
case 0 thus ?case by (auto simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp add: fw_upd_def upd_def)
qed
qed
lemma fw_middle_id:
"i ≤ n ⟹ j ≤ n ⟹ j' < j ⟹ i' ≤ i ⟹ fw m n 0 i' j' i j = m i j"
proof (induction i' arbitrary: j')
case 0 thus ?case
proof (induction j')
case 0 thus ?case by (simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp: fw_upd_def upd_def)
qed
next
case (Suc i') thus ?case
proof (induction j')
case 0 thus ?case using fw_innermost_id by (auto simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp add: fw_upd_def upd_def)
qed
qed
lemma fw_outermost_mono:
"i ≤ n ⟹ j ≤ n ⟹ fw m n 0 i j i j ≤ m i j"
proof (cases j)
case 0
assume "i ≤ n"
thus ?thesis
proof (cases i)
case 0 thus ?thesis using ‹j = 0› by (simp add: fw_upd_def upd_def)
next
case (Suc i')
hence "fw m n 0 i' n (Suc i') 0 = m (Suc i') 0" using fw_innermost_id[of "Suc i'" n 0 n i' m]
using ‹i ≤ n› by simp
thus ?thesis using ‹j = 0› Suc by (simp add: fw_upd_def upd_def)
qed
next
case (Suc j')
assume "i ≤ n" "j ≤ n"
hence "fw m n 0 i j' i (Suc j') = m i (Suc j')"
using fw_middle_id[of i n "Suc j'" j' i m] Suc by simp
thus ?thesis using Suc by (simp add: fw_upd_def upd_def)
qed
lemma Suc_innermost_id1:
"i ≤ n ⟹ j ≤ n ⟹ j' ≤ n ⟹ i' < i ⟹ fw m n (Suc k) i' j' i j = fw m n k i j i j"
proof (induction i' arbitrary: j')
case 0 thus ?case
proof (induction j')
case 0
hence "fw m n k n n i j = fw m n k i j i j" using single_iteration_inv[of i n j n n m k] by simp
thus ?case using 0 by (simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp: fw_upd_def upd_def)
qed
next
case (Suc i') thus ?case
proof (induction j')
case 0 thus ?case by (auto simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp add: fw_upd_def upd_def)
qed
qed
lemma Suc_innermost_id2:
"i ≤ n ⟹ j ≤ n ⟹ j' < j ⟹ i' ≤ i ⟹ fw m n (Suc k) i' j' i j = fw m n k i j i j"
proof (induction i' arbitrary: j')
case 0
hence "fw m n k n n i j = fw m n k i j i j" using single_iteration_inv[of i n j n n m k] by simp
with 0 show ?case
proof (induction j')
case 0
thus ?case by (auto simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp: fw_upd_def upd_def)
qed
next
case (Suc i') thus ?case
proof (induction j')
case 0 thus ?case using Suc_innermost_id1 by (auto simp add: fw_upd_def upd_def)
next
case (Suc j') thus ?case by (auto simp add: fw_upd_def upd_def)
qed
qed
lemma Suc_innermost_id1':
"i ≤ n ⟹ j ≤ n ⟹ j' ≤ n ⟹ i' < i ⟹ fw m n (Suc k) i' j' i j = fw m n k n n i j"
proof goal_cases
case 1
hence "fw m n (Suc k) i' j' i j = fw m n k i j i j" using Suc_innermost_id1 by simp
thus ?thesis using 1 single_iteration_inv[of i n] by simp
qed
lemma Suc_innermost_id2':
"i ≤ n ⟹ j ≤ n ⟹ j' < j ⟹ i' ≤ i ⟹ fw m n (Suc k) i' j' i j = fw m n k n n i j"
proof goal_cases
case 1
hence "fw m n (Suc k) i' j' i j = fw m n k i j i j" using Suc_innermost_id2 by simp
thus ?thesis using 1 single_iteration_inv[of i n] by simp
qed
lemma Suc_innermost_mono:
"i ≤ n ⟹ j ≤ n ⟹ fw m n (Suc k) i j i j ≤ fw m n k i j i j"
proof (cases j)
case 0
assume "i ≤ n"
thus ?thesis
proof (cases i)
case 0 thus ?thesis using ‹j = 0› single_iteration_inv[of 0 n 0 n n m k]
by (simp add: fw_upd_def upd_def)
next
case (Suc i')
thus ?thesis using Suc_innermost_id1 ‹i ≤ n› ‹j = 0›
by (auto simp: fw_upd_def upd_def local.min.coboundedI1)
qed
next
case (Suc j')
assume "i ≤ n" "j ≤ n"
thus ?thesis using Suc Suc_innermost_id2 by (auto simp: fw_upd_def upd_def local.min.coboundedI1)
qed
lemma fw_mono':
"i ≤ n ⟹ j ≤ n ⟹ fw m n k i j i j ≤ m i j"
proof (induction k)
case 0 thus ?case using fw_outermost_mono by simp
next
case (Suc k) thus ?case using Suc_innermost_mono[OF Suc.prems, of m k] by simp
qed
lemma fw_mono:
"i ≤ n ⟹ j ≤ n ⟹ i' ≤ n ⟹ j' ≤ n ⟹ fw m n k i j i' j' ≤ m i' j'"
proof (cases k)
case 0
assume 0: "i ≤ n" "j ≤ n" "i' ≤ n" "j' ≤ n" "k = 0"
thus ?thesis
proof (cases "i' ≤ i")
case False thus ?thesis using 0 fw_innermost_id by simp
next
case True thus ?thesis
proof (cases "j' ≤ j")
case True
have "fw m n 0 i j i' j' ≤ fw m n 0 i' j' i' j'" using fw_invariant True ‹i' ≤ i› 0 by simp
also have "fw m n 0 i' j' i' j' ≤ m i' j'" using 0 fw_outermost_mono by blast
finally show ?thesis by (simp add: ‹k = 0›)
next
case False thus ?thesis
proof (cases "i = i'", goal_cases)
case 1 then show ?thesis using fw_middle_id[of i' n j' j i' m] 0 by simp
next
case 2
then show ?case
using single_iteration_inv'[of i' i j' n j m 0] ‹i' ≤ i› fw_middle_id[of i' n j' j i' m]
fw_outermost_mono[of i' n j' m] 0
by simp
qed
qed
qed
next
case (Suc k)
assume prems: "i ≤ n" "j ≤ n" "i' ≤ n" "j' ≤ n"
thus ?thesis
proof (cases "i' ≤ i ∧ j' ≤ j")
case True
hence "fw m n (Suc k) i j i' j' = fw m n (Suc k) i' j' i' j'"
using prems single_iteration_inv by blast
thus ?thesis using Suc prems fw_mono' by auto
next
case False thus ?thesis
proof auto
assume "¬ i' ≤ i"
thus ?thesis using Suc prems fw_mono' Suc_innermost_id1 by auto
next
assume "¬ j' ≤ j"
hence "j < j'" by simp
show ?thesis
proof (cases "i ≤ i'")
case True
thus ?thesis using Suc prems Suc_innermost_id2 ‹j < j'› fw_mono' by auto
next
case False
thus ?thesis using single_iteration_inv' Suc prems fw_mono' by auto
qed
qed
qed
qed
lemma add_mono_neutr:
assumes "𝟭 ≤ b"
shows "a ≤ a + b"
using neutr add_mono assms by force
lemma add_mono_neutl:
assumes "𝟭 ≤ b"
shows "a ≤ b + a"
using neutr add_mono assms by force
lemma fw_step_0:
"m 0 0 ≥ 𝟭 ⟹ i ≤ n ⟹ j ≤ n ⟹ fw m n 0 i j i j = min (m i j) (m i 0 + m 0 j)"
proof (induction i)
case 0 thus ?case
proof (cases j)
case 0 thus ?thesis by (simp add: fw_upd_def upd_def)
next
case (Suc j)
hence "fw m n 0 0 j 0 (Suc j) = m 0 (Suc j)" using 0 fw_middle_id[of 0 n "Suc j" j 0 m] by fast
moreover have "fw m n 0 0 j 0 0 = m 0 0" using single_iteration_inv[of 0 0 0 j n m 0] Suc 0
by (auto simp add: fw_upd_def upd_def min_def intro: add_mono_neutl)
ultimately show ?thesis using Suc by (simp add: fw_upd_def upd_def)
qed
next
case (Suc i)
note A = this
show ?case
proof (cases j)
case 0
have "fw m n 0 i n (Suc i) 0 = m (Suc i) 0" using fw_innermost_id[of "Suc i" n 0 n i m] Suc by simp
moreover have "fw m n 0 i n 0 0 = m 0 0" using Suc single_iteration_inv[of 0 i 0 n n m 0]
by (auto simp add: fw_upd_def upd_def min_def intro: add_mono_neutl)
ultimately show ?thesis using 0 by (simp add: fw_upd_def upd_def)
next
case (Suc j)
have *: "fw m n 0 0 j 0 0 = m 0 0" using single_iteration_inv[ of 0 0 0 j n m 0] A Suc
by (auto simp add: fw_upd_def upd_def min_def intro: add_mono_neutl)
have **: "fw m n 0 i n 0 0 = m 0 0" using single_iteration_inv[of 0 i 0 n n m 0] A
by (auto simp add: fw_upd_def upd_def min_def intro: add_mono_neutl)
have "m 0 (Suc j) = fw_upd m 0 0 (Suc j) 0 (Suc j)" using ‹m 0 0 >= 𝟭›
by (auto simp add: fw_upd_def upd_def min_def intro: add_mono_neutl)
also have "… = fw m n 0 0 (Suc j) 0 (Suc j)" using fw_middle_id[of 0 n "Suc j" j 0 m] Suc A(4)
by (simp add: fw_upd_def upd_def *)
finally have ***: "fw m n 0 (Suc i) j 0 (Suc j) = m 0 (Suc j)"
using single_iteration_inv'[of 0 "Suc i" "Suc j" n j m 0] A Suc by simp
have "m (Suc i) 0 = fw_upd m 0 (Suc i) 0 (Suc i) 0" using ‹m 0 0 >= 𝟭›
by (auto simp add: fw_upd_def upd_def min_def intro: add_mono_neutr)
also have "… = fw m n 0 (Suc i) 0 (Suc i) 0"
using fw_innermost_id[of "Suc i" n 0 n i m] ‹Suc i ≤ n› ** by (simp add: fw_upd_def upd_def)
finally have "fw m n 0 (Suc i) j (Suc i) 0 = m (Suc i) 0"
using single_iteration_inv A Suc by auto
moreover have "fw m n 0 (Suc i) j (Suc i) (Suc j) = m (Suc i) (Suc j)"
using fw_middle_id A Suc by simp
ultimately show ?thesis using Suc *** by (simp add: fw_upd_def upd_def)
qed
qed
lemma fw_step_Suc:
"∀ k'≤n. fw m n k n n k' k' ≥ 𝟭 ⟹ i ≤ n ⟹ j ≤ n ⟹ Suc k ≤ n
⟹ fw m n (Suc k) i j i j = min (fw m n k n n i j) (fw m n k n n i (Suc k) + fw m n k n n (Suc k) j)"
proof (induction i)
case 0 thus ?case
proof (cases j)
case 0 thus ?thesis by (simp add: fw_upd_def upd_def)
next
case (Suc j)
then have
"fw m n k n n 0 (Suc j) = fw m n (Suc k) 0 j 0 (Suc j)"
using 0(2-) Suc_innermost_id2' by simp
moreover have "fw m n (Suc k) 0 j 0 (Suc k) = fw m n k n n 0 (Suc k)"
proof (cases "j < Suc k")
case True thus ?thesis using 0 Suc_innermost_id2' by simp
next
case False
hence
"fw m n (Suc k) 0 k 0 (Suc k) = fw m n k n n 0 (Suc k)"
using 0(2-) Suc Suc_innermost_id2' by simp
moreover have "fw m n (Suc k) 0 k (Suc k) (Suc k) = fw m n k n n (Suc k) (Suc k)"
using 0(2-) Suc Suc_innermost_id2' by simp
moreover have "fw m n (Suc k) 0 j 0 (Suc k) = fw m n (Suc k) 0 (Suc k) 0 (Suc k)"
using False single_iteration_inv 0(2-) Suc by force
ultimately show ?thesis using 0(1)
by (auto simp add: fw_upd_def upd_def ‹Suc k ≤ n› min_def intro: add_mono_neutr)
qed
moreover have "fw m n k n n (Suc k) (Suc j) = fw m n (Suc k) 0 j (Suc k) (Suc j)"
using 0(2-) Suc Suc_innermost_id2' by simp
ultimately show ?thesis using Suc by (simp add: fw_upd_def upd_def)
qed
next
case (Suc i)
note A = this
show ?case
proof (cases j)
case 0
hence
"fw m n (Suc k) i n (Suc i) 0 = fw m n k n n (Suc i) 0"
using Suc_innermost_id1' ‹Suc i ≤ n› by simp
moreover have "fw m n (Suc k) i n (Suc i) (Suc k) = fw m n k n n (Suc i) (Suc k)"
using Suc_innermost_id1' A(3,5) by simp
moreover have "fw m n (Suc k) i n (Suc k) 0 = fw m n k n n (Suc k) 0"
proof (cases "i < Suc k")
case True thus ?thesis using Suc_innermost_id1' A(3,5) by simp
next
case False
have "fw m n (Suc k) k n (Suc k) (Suc k) = fw m n k n n (Suc k) (Suc k)"
using Suc_innermost_id1' ‹Suc i ≤ n› False by simp
moreover have "fw m n (Suc k) k n (Suc k) 0 = fw m n k n n (Suc k) 0"
using Suc_innermost_id1' ‹Suc i ≤ n› False by simp
moreover have "fw m n (Suc k) i n (Suc k) 0 = fw m n (Suc k) (Suc k) 0 (Suc k) 0"
using single_iteration_inv ‹Suc i ≤ n› False by simp
ultimately show ?thesis using Suc(2)
by (auto simp add: fw_upd_def upd_def ‹Suc k ≤ n› min_def intro: add_mono_neutl)
qed
ultimately show ?thesis using 0 by (simp add: fw_upd_def upd_def)
next
case (Suc j)
hence "fw m n (Suc k) (Suc i) j (Suc i) (Suc j) = fw m n k n n (Suc i) (Suc j)"
using Suc_innermost_id2' A(3,4) by simp
moreover have "fw m n (Suc k) (Suc i) j (Suc i) (Suc k) = fw m n k n n (Suc i) (Suc k)"
proof (cases "j < Suc k")
case True thus ?thesis using Suc A(3-) Suc_innermost_id2' by simp
next
case False
have *:"fw m n (Suc k) (Suc i) k (Suc i) (Suc k) = fw m n k n n (Suc i) (Suc k)"
using Suc_innermost_id2' A(3,5) by simp
have **:"fw m n (Suc k) (Suc i) k (Suc k) (Suc k) = fw m n k n n (Suc k) (Suc k)"
proof (cases "Suc i ≤ Suc k")
case True thus ?thesis using Suc_innermost_id2' A(5) by simp
next
case False
hence "fw m n (Suc k) (Suc i) k (Suc k) (Suc k) = fw m n (Suc k) (Suc k) (Suc k) (Suc k) (Suc k)"
using single_iteration_inv'[of "Suc k" "Suc i" "Suc k" n k m "Suc k"] A(3) by simp
moreover have "fw m n (Suc k) (Suc k) k (Suc k) (Suc k) = fw m n k n n (Suc k) (Suc k)"
using Suc_innermost_id2' A(5) by simp
ultimately show ?thesis using A(2)
by (auto simp add: fw_upd_def upd_def ‹Suc k ≤ n› min_def intro: add_mono_neutl)
qed
have "fw m n (Suc k) (Suc i) j (Suc i) (Suc k) = fw m n (Suc k) (Suc i) (Suc k) (Suc i) (Suc k)"
using False single_iteration_inv[of "Suc i" "Suc i" "Suc k" j n m "Suc k"] A(3-) Suc by simp
also have "… = fw m n k n n (Suc i) (Suc k)" using * ** A(2)
by (auto simp add: fw_upd_def upd_def ‹Suc k ≤ n› min_def intro: add_mono_neutr)
finally show ?thesis by simp
qed
moreover have "fw m n (Suc k) (Suc i) j (Suc k) (Suc j) = fw m n k n n (Suc k) (Suc j)"
proof (cases "Suc i ≤ Suc k")
case True thus ?thesis using Suc_innermost_id2' Suc A(3-5) by simp
next
case False
have "fw m n (Suc k) (Suc k) j (Suc k) (Suc k) = fw m n k n n (Suc k) (Suc k)"
proof (cases "j < Suc k")
case True thus ?thesis using Suc_innermost_id2' A(5) by simp
next
case False
hence "fw m n (Suc k) (Suc k) j (Suc k) (Suc k) = fw m n (Suc k) (Suc k) (Suc k) (Suc k) (Suc k)"
using single_iteration_inv A(3,4) Suc by simp
moreover have "fw m n (Suc k) (Suc k) k (Suc k) (Suc k) = fw m n k n n (Suc k) (Suc k)"
using Suc_innermost_id2' A(5) by simp
ultimately show ?thesis using A(2)
by (auto simp add: fw_upd_def upd_def ‹Suc k ≤ n› min_def intro: add_mono_neutl)
qed
moreover have "fw m n (Suc k) (Suc k) j (Suc k) (Suc j) = fw m n k n n (Suc k) (Suc j)"
using Suc_innermost_id2' Suc A(3-5) by simp
ultimately have "fw m n (Suc k) (Suc k) (Suc j) (Suc k) (Suc j) = fw m n k n n (Suc k) (Suc j)"
using A(2) by (auto simp add: fw_upd_def upd_def ‹Suc k ≤ n› min_def intro: add_mono_neutl)
moreover have "fw m n (Suc k) (Suc i) j (Suc k) (Suc j) = fw m n (Suc k) (Suc k) (Suc j) (Suc k) (Suc j)"
using single_iteration_inv'[of "Suc k" "Suc i" "Suc j" n j m "Suc k"] Suc A(3-) False by simp
moreover have "fw m n (Suc k) (Suc k) k (Suc k) (Suc k) = fw m n k n n (Suc k) (Suc k)"
using Suc_innermost_id2' A(5) by simp
ultimately show ?thesis using A(2) by (simp add: fw_upd_def upd_def)
qed
ultimately show ?thesis using Suc by (simp add: fw_upd_def upd_def)
qed
qed
subsection ‹Length of Paths›
fun len :: "'a mat ⇒ nat ⇒ nat ⇒ nat list ⇒ 'a" where
"len m u v [] = m u v" |
"len m u v (w#ws) = m u w + len m w v ws"
lemma len_decomp: "xs = ys @ y # zs ⟹ len m x z xs = len m x y ys + len m y z zs"
by (induction ys arbitrary: x xs) (simp add: assoc)+
lemma len_comp: "len m a c (xs @ b # ys) = len m a b xs + len m b c ys"
by (induction xs arbitrary: a) (auto simp: assoc)
subsection ‹Shortening Negative Cycles›
lemma remove_cycles_neg_cycles_aux:
fixes i xs ys
defines "xs' ≡ i # ys"
assumes "i ∉ set ys"
assumes "i ∈ set xs"
assumes "xs = as @ concat (map ((#) i) xss) @ xs'"
assumes "len m i j ys > len m i j xs"
shows "∃ ys. set ys ⊆ set xs ∧ len m i i ys < 𝟭" using assms
proof (induction xss arbitrary: xs as)
case Nil
with Nil show ?case
proof (cases "len m i i as ≥ 𝟭", goal_cases)
case 1
from this(4,6) len_decomp[of xs as i ys m i j]
have "len m i j xs = len m i i as + len m i j ys" by simp
with 1(11)
have "len m i j ys ≤ len m i j xs" using add_mono by fastforce
thus ?thesis using Nil(5) by auto
next
case 2 thus ?case by auto
qed
next
case (Cons zs xss)
let ?xs = "zs @ concat (map ((#) i) xss) @ xs'"
from Cons show ?case
proof (cases "len m i i as ≥ 𝟭", goal_cases)
case 1
from this(5,7) len_decomp add_mono
have "len m i j ?xs ≤ len m i j xs" by fastforce
hence 4:"len m i j ?xs < len m i j ys" using 1(6) by simp
have 2:"i ∈ set ?xs" using Cons(2) by auto
have "set ?xs ⊆ set xs" using Cons(5) by auto
moreover from Cons(1)[OF 1(2,3) 2 _ 4] have "∃ys. set ys ⊆ set ?xs ∧ len m i i ys < 𝟭" by auto
ultimately show ?case by blast
next
case 2
from this(5,7) show ?case by auto
qed
qed
lemma add_lt_neutral: "a + b < b ⟹ a < 𝟭"
proof (rule ccontr)
assume "a + b < b" "¬ a < 𝟭"
hence "a ≥ 𝟭" by auto
from add_mono[OF this, of b b] ‹a + b < b› show False by auto
qed
lemma remove_cycles_neg_cycles_aux':
fixes j xs ys
assumes "j ∉ set ys"
assumes "j ∈ set xs"
assumes "xs = ys @ j # concat (map (λ xs. xs @ [j]) xss) @ as"
assumes "len m i j ys > len m i j xs"
shows "∃ ys. set ys ⊆ set xs ∧ len m j j ys < 𝟭" using assms
proof (induction xss arbitrary: xs as)
case Nil
show ?case
proof (cases "len m j j as ≥ 𝟭")
case True
from Nil(3) len_decomp[of xs ys j as m i j]
have "len m i j xs = len m i j ys + len m j j as" by simp
with True
have "len m i j ys ≤ len m i j xs" using add_mono by fastforce
with Nil show ?thesis by auto
next
case False with Nil show ?thesis by auto
qed
next
case (Cons zs xss)
let ?xs = "ys @ j # concat (map (λxs. xs @ [j]) xss) @ as"
let ?t = "concat (map (λxs. xs @ [j]) xss) @ as"
show ?case
proof (cases "len m i j ?xs ≤ len m i j xs")
case True
hence 4:"len m i j ?xs < len m i j ys" using Cons(5) by simp
have 2:"j ∈ set ?xs" using Cons(2) by auto
have "set ?xs ⊆ set xs" using Cons(4) by auto
moreover from Cons(1)[OF Cons(2) 2 _ 4] have "∃ys. set ys ⊆ set ?xs ∧ len m j j ys < 𝟭" by blast
ultimately show ?thesis by blast
next
case False
hence "len m i j xs < len m i j ?xs" by auto
from this len_decomp Cons(4) add_mono
have "len m j j (concat (map (λxs. xs @ [j]) (zs # xss)) @ as) < len m j j ?t"
using False local.leI by fastforce
hence "len m j j (zs @ j # ?t) < len m j j ?t" by simp
with len_decomp[of "zs @ j # ?t" zs j ?t m j j]
have "len m j j zs + len m j j ?t < len m j j ?t" by auto
hence "len m j j zs < 𝟭" using add_lt_neutral by auto
thus ?thesis using Cons.prems(3) by auto
qed
qed
lemma add_le_impl: "a + b < a + c ⟹ b < c"
proof (rule ccontr)
assume "a + b < a + c" "¬ b < c"
hence "b ≥ c" by auto
from add_mono[OF _ this, of a a] ‹a + b < a + c› show False by auto
qed
lemma start_remove_neg_cycles:
"len m i j (start_remove xs k []) > len m i j xs ⟹ ∃ ys. set ys ⊆ set xs ∧ len m k k ys < 𝟭"
proof-
let ?xs = "start_remove xs k []"
assume len_lt:"len m i j ?xs > len m i j xs"
hence "k ∈ set xs" using start_remove_id by fastforce
from start_remove_decomp[OF this, of "[]"] obtain as bs where as_bs:
"xs = as @ k # bs" "?xs = as @ remove_cycles bs k [k]"
by fastforce
let ?xs' = "remove_cycles bs k [k]"
have "k ∈ set bs" using as_bs len_lt remove_cycles_id by fastforce
then obtain ys where ys: "?xs = as @ k # ys" "?xs' = k # ys" "k ∉ set ys"
using as_bs(2) remove_cycles_begins_with[OF ‹k ∈ set bs›] by auto
have len_lt': "len m k j bs < len m k j ys"
using len_decomp[OF as_bs(1), of m i j] len_decomp[OF ys(1), of m i j] len_lt add_le_impl by metis
from remove_cycles_cycles[OF ‹k ∈ set bs›] obtain xss as'
where "as' @ concat (map ((#) k) xss) @ ?xs' = bs" by fastforce
hence "as' @ concat (map ((#) k) xss) @ k # ys = bs" using ys(2) by simp
from remove_cycles_neg_cycles_aux[OF ‹k ∉ set ys› ‹k ∈ set bs› this[symmetric] len_lt']
show ?thesis using as_bs(1) by auto
qed
lemma remove_all_cycles_neg_cycles:
"len m i j (remove_all_cycles ys xs) > len m i j xs
⟹ ∃ ys k. set ys ⊆ set xs ∧ k ∈ set xs ∧ len m k k ys < 𝟭"
proof (induction ys arbitrary: xs)
case Nil thus ?case by auto
next
case (Cons y ys)
let ?xs = "start_remove xs y []"
show ?case
proof (cases "len m i j xs < len m i j ?xs")
case True
with start_remove_id have "y ∈ set xs" by fastforce
with start_remove_neg_cycles[OF True] show ?thesis by blast
next
case False
with Cons(2) have "len m i j ?xs < len m i j (remove_all_cycles (y # ys) xs)" by auto
hence "len m i j ?xs < len m i j (remove_all_cycles ys ?xs)" by auto
from Cons(1)[OF this] show ?thesis using start_remove_subs[of xs y "[]"] by auto
qed
qed
lemma (in -) concat_map_cons_rev:
"rev (concat (map ((#) j) xss)) = concat (map (λ xs. xs @ [j]) (rev (map rev xss)))"
by (induction xss) auto
lemma negative_cycle_dest: "len m i j (rem_cycles i j xs) > len m i j xs
⟹ ∃ i' ys. len m i' i' ys < 𝟭 ∧ set ys ⊆ set xs ∧ i' ∈ set (i # j # xs)"
proof -
let ?xsij = "rem_cycles i j xs"
let ?xsj = "remove_all_rev j (remove_all_cycles xs xs)"
let ?xs = "remove_all_cycles xs xs"
assume len_lt: "len m i j ?xsij > len m i j xs"
show ?thesis
proof (cases "len m i j ?xsij ≤ len m i j ?xsj")
case True
hence len_lt: "len m i j ?xsj > len m i j xs" using len_lt by simp
show ?thesis
proof (cases "len m i j ?xsj ≤ len m i j ?xs")
case True
hence "len m i j ?xs > len m i j xs" using len_lt by simp
with remove_all_cycles_neg_cycles[OF this] show ?thesis by auto
next
case False
then have len_lt': "len m i j ?xsj > len m i j ?xs" by simp
show ?thesis
proof (cases "j ∈ set ?xs")
case False
thus ?thesis using len_lt' by (simp add: remove_all_rev_def)
next
case True
from remove_all_rev_removes[of j] have 1: "j ∉ set ?xsj" by simp
from True have "j ∈ set (rev ?xs)" by auto
from remove_cycles_cycles[OF this] obtain xss as where as:
"as @ concat (map ((#) j) xss) @ remove_cycles (rev ?xs) j [] = rev ?xs" "j ∉ set as"
by blast
from True have "?xsj = rev (tl (remove_cycles (rev ?xs) j []))" by (simp add: remove_all_rev_def)
with remove_cycles_begins_with[OF ‹j ∈ set (rev ?xs)›, of "[]"]
have "remove_cycles (rev ?xs) j [] = j # rev ?xsj" "j ∉ set ?xsj"
by auto
with as(1) have xss: "as @ concat (map ((#) j) xss) @ j # rev ?xsj = rev ?xs" by simp
hence "rev (as @ concat (map ((#) j) xss) @ j # rev ?xsj) = ?xs" by simp
hence "?xsj @ j # rev (concat (map ((#) j) xss)) @ rev as = ?xs" by simp
hence "?xsj @ j # concat (map (λ xs. xs @ [j]) (rev (map rev xss))) @ rev as = ?xs"
by (simp add: concat_map_cons_rev)
from remove_cycles_neg_cycles_aux'[OF 1 True this[symmetric] len_lt']
show ?thesis using remove_all_cycles_subs by fastforce
qed
qed
next
case False
hence len_lt': "len m i j ?xsij > len m i j ?xsj" by simp
show ?thesis
proof (cases "i ∈ set ?xsj")
case False
thus ?thesis using len_lt' by (simp add: remove_all_def)
next
case True
from remove_all_removes[of i] have 1: "i ∉ set ?xsij" by (simp add: remove_all_def)
from remove_cycles_cycles[OF True] obtain xss as where as:
"as @ concat (map ((#) i) xss) @ remove_cycles ?xsj i [] = ?xsj" "i ∉ set as" by blast
from True have "?xsij = tl (remove_cycles ?xsj i [])" by (simp add: remove_all_def)
with remove_cycles_begins_with[OF True, of "[]"]
have "remove_cycles ?xsj i [] = i # ?xsij" "i ∉ set ?xsij"
by auto
with as(1) have xss: "as @ concat (map ((#) i) xss) @ i # ?xsij = ?xsj" by simp
from remove_cycles_neg_cycles_aux[OF 1 True this[symmetric] len_lt']
show ?thesis using remove_all_rev_subs remove_all_cycles_subs by fastforce
qed
qed
qed
section ‹Definition of Shortest Paths›
definition D :: "'a mat ⇒ nat ⇒ nat ⇒ nat ⇒ 'a" where
"D m i j k ≡ Min {len m i j xs | xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
lemma (in -) distinct_length_le:"finite s ⟹ set xs ⊆ s ⟹ distinct xs ⟹ length xs ≤ card s"
by (metis card_mono distinct_card)
lemma D_base_finite:
"finite {len m i j xs | xs. set xs ⊆ {0..k} ∧ distinct xs}"
using finite_subset_distinct finite_image_set by blast
lemma D_base_finite':
"finite {len m i j xs | xs. set xs ⊆ {0..k} ∧ distinct (i # j # xs)}"
proof -
have "{len m i j xs | xs. set xs ⊆ {0..k} ∧ distinct (i # j # xs)}
⊆ {len m i j xs | xs. set xs ⊆ {0..k} ∧ distinct xs}" by auto
with D_base_finite[of m i j k] show ?thesis by (rule rev_finite_subset)
qed
lemma D_base_finite'':
"finite {len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
using D_base_finite[of m i j k] by - (rule finite_subset, auto)
definition cycle_free :: "'a mat ⇒ nat ⇒ bool" where
"cycle_free m n ≡ ∀ i xs. i ≤ n ∧ set xs ⊆ {0..n} ⟶
(∀ j. j ≤ n ⟶ len m i j (rem_cycles i j xs) ≤ len m i j xs) ∧ len m i i xs ≥ 𝟭"
lemma D_eqI:
fixes m n i j k
defines "A ≡ {len m i j xs | xs. set xs ⊆ {0..k}}"
defines "A_distinct ≡ {len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
assumes "cycle_free m n" "i ≤ n" "j ≤ n" "k ≤ n" "(⋀y. y ∈ A_distinct ⟹ x ≤ y)" "x ∈ A"
shows "D m i j k = x" using assms
proof -
let ?S = "{len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
show ?thesis unfolding D_def
proof (rule Min_eqI)
have "?S ⊆ {len m i j xs |xs. set xs ⊆ {0..k} ∧ distinct xs}" by auto
thus "finite {len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
using D_base_finite[of m i j k] by (rule finite_subset)
next
fix y assume "y ∈ ?S"
hence "y ∈ A_distinct" using assms(2,7) by fastforce
thus "x ≤ y" using assms by meson
next
from assms obtain xs where xs: "x = len m i j xs" "set xs ⊆ {0..k}" by auto
let ?ys = "rem_cycles i j xs"
let ?y = "len m i j ?ys"
from assms(3-6) xs have *:"?y ≤ x" by (fastforce simp add: cycle_free_def)
have distinct: "i ∉ set ?ys" "j ∉ set ?ys" "distinct ?ys"
using rem_cycles_distinct remove_all_removes rem_cycles_removes_last by fast+
with xs(2) have "?y ∈ A_distinct" unfolding A_distinct_def using rem_cycles_subs by fastforce
hence "x ≤ ?y" using assms by meson
moreover have "?y ≤ x" using assms(3-6) xs by (fastforce simp add: cycle_free_def)
ultimately have "x = ?y" by simp
thus "x ∈ ?S" using distinct xs(2) rem_cycles_subs[of i j xs] by fastforce
qed
qed
lemma D_base_not_empty:
"{len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs} ≠ {}"
proof -
have "len m i j [] ∈ {len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
by fastforce
thus ?thesis by auto
qed
lemma Min_elem_dest: "finite A ⟹ A ≠ {} ⟹ x = Min A ⟹ x ∈ A" by simp
lemma D_dest: "x = D m i j k ⟹
x ∈ {len m i j xs |xs. set xs ⊆ {0..Suc k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
using Min_elem_dest[OF D_base_finite'' D_base_not_empty] by (fastforce simp add: D_def)
lemma D_dest': "x = D m i j k ⟹ x ∈ {len m i j xs |xs. set xs ⊆ {0..Suc k}}"
using Min_elem_dest[OF D_base_finite'' D_base_not_empty] by (fastforce simp add: D_def)
lemma D_dest'': "x = D m i j k ⟹ x ∈ {len m i j xs |xs. set xs ⊆ {0..k}}"
using Min_elem_dest[OF D_base_finite'' D_base_not_empty] by (fastforce simp add: D_def)
lemma cycle_free_loop_dest: "i ≤ n ⟹ set xs ⊆ {0..n} ⟹ cycle_free m n ⟹ len m i i xs ≥ 𝟭"
unfolding cycle_free_def by auto
lemma cycle_free_dest:
"cycle_free m n ⟹ i ≤ n ⟹ j ≤ n ⟹ set xs ⊆ {0..n}
⟹ len m i j (rem_cycles i j xs) ≤ len m i j xs"
by (auto simp add: cycle_free_def)
definition cycle_free_up_to :: "'a mat ⇒ nat ⇒ nat ⇒ bool" where
"cycle_free_up_to m k n ≡ ∀ i xs. i ≤ n ∧ set xs ⊆ {0..k} ⟶
(∀ j. j ≤ n ⟶ len m i j (rem_cycles i j xs) ≤ len m i j xs) ∧ len m i i xs ≥ 𝟭"
lemma cycle_free_up_to_loop_dest:
"i ≤ n ⟹ set xs ⊆ {0..k} ⟹ cycle_free_up_to m k n ⟹ len m i i xs ≥ 𝟭"
unfolding cycle_free_up_to_def by auto
lemma cycle_free_up_to_diag:
assumes "cycle_free_up_to m k n" "i ≤ n"
shows "m i i ≥ 𝟭"
using cycle_free_up_to_loop_dest[OF assms(2) _ assms(1), of "[]"] by auto
lemma D_eqI2:
fixes m n i j k
defines "A ≡ {len m i j xs | xs. set xs ⊆ {0..k}}"
defines "A_distinct ≡ {len m i j xs | xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
assumes "cycle_free_up_to m k n" "i ≤ n" "j ≤ n" "k ≤ n"
"(⋀y. y ∈ A_distinct ⟹ x ≤ y)" "x ∈ A"
shows "D m i j k = x" using assms
proof -
show ?thesis
proof (simp add: D_def A_distinct_def[symmetric], rule Min_eqI)
show "finite A_distinct" using D_base_finite''[of m i j k] unfolding A_distinct_def by auto
next
fix y assume "y ∈ A_distinct"
thus "x ≤ y" using assms by meson
next
from assms obtain xs where xs: "x = len m i j xs" "set xs ⊆ {0..k}" by auto
let ?ys = "rem_cycles i j xs"
let ?y = "len m i j ?ys"
from assms(3-6) xs have *:"?y ≤ x" by (fastforce simp add: cycle_free_up_to_def)
have distinct: "i ∉ set ?ys" "j ∉ set ?ys" "distinct ?ys"
using rem_cycles_distinct remove_all_removes rem_cycles_removes_last by fast+
with xs(2) have "?y ∈ A_distinct" unfolding A_distinct_def using rem_cycles_subs by fastforce
hence "x ≤ ?y" using assms by meson
moreover have "?y ≤ x" using assms(3-6) xs by (fastforce simp add: cycle_free_up_to_def)
ultimately have "x = ?y" by simp
then show "x ∈ A_distinct" using distinct xs(2) rem_cycles_subs[of i j xs]
unfolding A_distinct_def by fastforce
qed
qed
section ‹Result Under The Absence of Negative Cycles›
text ‹
This proves that the algorithm correctly computes shortest paths under the absence of negative
cycles by a standard argument.
›
theorem fw_shortest_path_up_to:
"cycle_free_up_to m k n ⟹ i' ≤ i ⟹ j' ≤ j ⟹ i ≤ n ⟹ j ≤ n ⟹ k ≤ n
⟹ D m i' j' k = fw m n k i j i' j'"
proof (induction k arbitrary: i j i' j')
case 0
from cycle_free_up_to_diag[OF 0(1)] have diag: "∀ k ≤ n. m k k ≥ 𝟭" by auto
then have m_diag: "m 0 0 ≥ 𝟭" by simp
let ?S = "{len m i' j' xs |xs. set xs ⊆ {0} ∧ i' ∉ set xs ∧ j' ∉ set xs ∧ distinct xs}"
show ?case unfolding D_def
proof (simp, rule Min_eqI)
have "?S ⊆ {len m i' j' xs |xs. set xs ⊆ {0..0} ∧ distinct xs}" by auto
thus "finite ?S" using D_base_finite[of m i' j' 0] by (rule finite_subset)
next
fix l assume "l ∈ ?S"
then obtain xs where l: "l = len m i' j' xs" and xs: "xs = [] ∨ xs = [0]"
using distinct_list_single_elem_decomp by auto
{ assume "xs = []"
have "fw m n 0 i j i' j' ≤ fw m n 0 0 0 i' j'" using fw_invariant 0 by blast
also have "… ≤ m i' j'" by (cases "i' = 0 ∧ j' = 0") (simp add: fw_upd_def upd_def)+
finally have "fw m n 0 i j i' j' ≤ l" using ‹xs = []› l by simp
}
moreover
{ assume "xs = [0]"
have "fw m n 0 i j i' j' ≤ fw m n 0 i' j' i' j'" using fw_invariant 0 by blast
also have "… ≤ m i' 0 + m 0 j'"
proof (cases j')
assume "j' = 0"
show ?thesis
proof (cases i')
assume "i' = 0"
thus ?thesis using ‹j' = 0› by (simp add: fw_upd_def upd_def)
next
fix i'' assume i'': "i' = Suc i''"
have "fw_upd (fw m n 0 i'' n) 0 (Suc i'') 0 (Suc i'') 0 ≤ fw m n 0 i'' n (Suc i'') 0"
by (simp add: fw_upd_mono)
also have "… ≤ m (Suc i'') 0" using fw_mono 0 i'' by simp
finally show ?thesis using ‹j' = 0› m_diag i'' neutr add_mono by fastforce
qed
next
fix j'' assume j'': "j' = Suc j''"
have "fw_upd (fw m n 0 i' j'') 0 i' (Suc j'') i' (Suc j'')
≤ fw m n 0 i' j'' i' 0 + fw m n 0 i' j'' 0 (Suc j'') "
by (simp add: fw_upd_def upd_def)
also have "… ≤ m i' 0 + m 0 (Suc j'')"
using fw_mono[of i' n j'' i' 0 m 0] fw_mono[of i' n j'' 0 "Suc j''" m 0 ] j'' 0
by (simp add: add_mono)
finally show ?thesis using j'' by simp
qed
finally have "fw m n 0 i j i' j' ≤ l" using ‹xs = [0]› l by simp
}
ultimately show "fw m n 0 i j i' j' ≤ l" using xs by auto
next
have A: "fw m n 0 i j i' j' = fw m n 0 i' j' i' j'" using single_iteration_inv 0 by blast
have "fw m n 0 i' j' i' j' = min (m i' j') (m i' 0 + m 0 j')"
using 0 by (simp add: fw_step_0[of m, OF m_diag])
hence
"fw m n 0 i' j' i' j' = m i' j'
∨ (fw m n 0 i' j' i' j' = m i' 0 + m 0 j'∧ m i' 0 + m 0 j' ≤ m i' j')"
by (auto simp add: ord.min_def)
thus "fw m n 0 i j i' j' ∈ ?S"
proof (standard, goal_cases)
case 1
hence "fw m n 0 i j i' j' = len m i' j' []" using A by auto
thus ?case by fastforce
next
case 2
hence *:"fw m n 0 i j i' j' = len m i' j' [0]" using A by auto
thus ?case
proof (cases "i' = 0 ∨ j' = 0")
case False thus ?thesis using * by fastforce
next
case True
{ assume "i' = 0"
from diag have "m 0 0 + m 0 j' ≥ m 0 j'" by (auto intro: add_mono_neutl)
with ‹i' = 0› have "fw m n 0 i j i' j' = len m 0 j' []" using 0 A 2 by auto
} moreover
{ assume "j' = 0"
from diag have "m i' 0 + m 0 0 ≥ m i' 0" by (auto intro: add_mono_neutr)
with ‹j' = 0› have "fw m n 0 i j i' j' = len m i' 0 []" using 0 A 2 by auto
}
ultimately have "fw m n 0 i j i' j' = len m i' j' []" using True by auto
then show ?thesis by fastforce
qed
qed
qed
next
case (Suc k)
from cycle_free_up_to_diag[OF Suc.prems(1)] have diag: "∀ k ≤ n. m k k ≥ 𝟭" by auto
from Suc.prems have cycle_free_to_k:
"cycle_free_up_to m k n" by (fastforce simp add: cycle_free_up_to_def)
{ fix k' assume "k' ≤ n"
with Suc cycle_free_to_k have "D m k' k' k = fw m n k n n k' k'" by auto
from D_dest''[OF this[symmetric]] obtain xs where
"set xs ⊆ {0..k}" "fw m n k n n k' k'= len m k' k' xs"
by auto
with Suc(2) ‹Suc k ≤ n› ‹k' ≤ n› have "fw m n k n n k' k' ≥ 𝟭"
unfolding cycle_free_up_to_def by force
}
hence K: "∀k'≤n. fw m n k n n k' k' ≥ 𝟭" by simp
let ?S = "λ k i j. {len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
show ?case
proof (rule D_eqI2)
show "cycle_free_up_to m (Suc k) n" using Suc.prems(1) .
next
show "i' ≤ n" using Suc.prems by simp
next
show "j' ≤ n" using Suc.prems by simp
next
show "Suc k ≤ n" using Suc.prems by simp
next
fix l assume "l ∈ {len m i' j' xs | xs. set xs ⊆ {0..Suc k} ∧ i' ∉ set xs ∧ j' ∉ set xs ∧ distinct xs}"
then obtain xs where xs:
"l = len m i' j' xs" "set xs ⊆ {0..Suc k}" "i' ∉ set xs" "j' ∉ set xs" "distinct xs"
by auto
have IH: "D m i' j' k = fw m n k i j i' j'" using cycle_free_to_k Suc by auto
have fin:
"finite {len m i' j' xs |xs. set xs ⊆ {0..k} ∧ i' ∉ set xs ∧ j' ∉ set xs ∧ distinct xs}"
using D_base_finite'' by simp
show "fw m n (Suc k) i j i' j' ≤ l"
proof (cases "Suc k ∈ set xs")
case False
hence "set xs ⊆ {0..k}" using xs(2) using atLeastAtMostSuc_conv by auto
hence
"l ∈ {len m i' j' xs | xs. set xs ⊆ {0..k} ∧ i' ∉ set xs ∧ j' ∉ set xs ∧ distinct xs}"
using xs by auto
with Min_le[OF fin this] have "fw m n k i j i' j' ≤ l" using IH by (simp add: D_def)
thus ?thesis using fw_invariant[of k "Suc k" i n j j i m i' j'] Suc.prems by simp
next
case True
then obtain ys zs where ys_zs_id: "xs = ys @ Suc k # zs" by (meson split_list)
with xs(5) have ys_zs: "distinct ys" "distinct zs" "Suc k ∉ set ys" "Suc k ∉ set zs"
"set ys ∩ set zs = {}" by auto
have "i' ≠ Suc k" "j' ≠ Suc k" using xs(3,4) True by auto
have "set ys ⊆ {0..k}" using ys_zs(3) xs(2) ys_zs_id using atLeastAtMostSuc_conv by auto
hence "len m i' (Suc k) ys ∈ ?S k i' (Suc k)" using ys_zs_id ys_zs xs(3) by fastforce
with Min_le[OF _ this] have "Min (?S k i' (Suc k)) ≤ len m i' (Suc k) ys"
using D_base_finite'[of m i' "Suc k" k] ‹i' ≠ Suc k› by fastforce
moreover have "fw m n k n n i' (Suc k) = D m i' (Suc k) k"
using Suc.IH[OF cycle_free_to_k, of i' n] Suc.prems by auto
ultimately have *:"fw m n k n n i' (Suc k) ≤ len m i' (Suc k) ys" using ‹i' ≠ Suc k›
by (auto simp: D_def)
have "set zs ⊆ {0..k}" using ys_zs(4) xs(2) ys_zs_id using atLeastAtMostSuc_conv by auto
hence "len m (Suc k) j' zs ∈ ?S k (Suc k) j'" using ys_zs_id ys_zs xs(3,4,5) by fastforce
with Min_le[OF _ this] have "Min (?S k (Suc k) j') ≤ len m (Suc k) j' zs"
using D_base_finite'[of m "Suc k" j' k] ‹j' ≠ Suc k› by fastforce
moreover have "fw m n k n n (Suc k) j' = D m (Suc k) j' k"
using Suc.IH[OF cycle_free_to_k, of "Suc k" n j' n] Suc.prems by auto
ultimately have **:"fw m n k n n (Suc k) j' ≤ len m (Suc k) j' zs" using ‹j' ≠ Suc k›
by (auto simp: D_def)
have len_eq: "l = len m i' (Suc k) ys + len m (Suc k) j' zs"
by (simp add: xs(1) len_decomp[OF ys_zs_id, symmetric] ys_zs_id)
have "fw m n (Suc k) i' j' i' j' ≤ fw m n k n n i' (Suc k) + fw m n k n n (Suc k) j'"
using fw_step_Suc[of n m k i' j', OF K] Suc.prems(2-) by simp
hence "fw m n (Suc k) i' j' i' j' ≤ l"
using fw_step_Suc[of n m k i j] Suc.prems(3-) * ** len_eq add_mono by fastforce
thus ?thesis using fw_invariant[of "Suc k" "Suc k" i n j j' i' m i' j'] Suc.prems(2-) by simp
qed
next
have "fw m n (Suc k) i j i' j' = fw m n (Suc k) i' j' i' j'"
using single_iteration_inv[OF Suc.prems(2-5)] .
also have "… = min (fw m n k n n i' j') (fw m n k n n i' (Suc k) + fw m n k n n (Suc k) j')"
using fw_step_Suc[OF K] Suc.prems(2-) by simp
finally show "fw m n (Suc k) i j i' j' ∈ {len m i' j' xs | xs. set xs ⊆ {0..Suc k}}"
proof (cases "fw m n (Suc k) i j i' j' = fw m n k n n i' j'", goal_cases)
case True
have "fw m n (Suc k) i j i' j' = D m i' j' k"
using Suc.IH[OF cycle_free_to_k, of i' n j' n] Suc.prems(2-) True by simp
from D_dest'[OF this] show ?thesis by blast
next
case 2
hence A:"fw m n (Suc k) i j i' j' = fw m n k n n i' (Suc k) + fw m n k n n (Suc k) j'"
by (metis ord.min_def)
have "fw m n k n n i' j' = D m i' j' k"
using Suc.IH[OF cycle_free_to_k, of i' n j' n] Suc.prems by simp
from D_dest[OF this] have B:"fw m n k n n i' j' ∈ ?S (Suc k) i' j'"
by blast
have "fw m n k n n i' (Suc k) = D m i' (Suc k) k"
using Suc.IH[OF cycle_free_to_k, of i' n "Suc k" n] Suc.prems by simp
from D_dest'[OF this] obtain xs where xs:
"fw m n k n n i' (Suc k) = len m i' (Suc k) xs" "set xs ⊆ {0..Suc k}" by blast
have "fw m n k n n (Suc k) j' = D m (Suc k) j' k"
using Suc.IH[OF cycle_free_to_k, of "Suc k" n j' n] Suc.prems by simp
from D_dest'[OF this] obtain ys where ys:
"fw m n k n n (Suc k) j' = len m (Suc k) j' ys" "set ys ⊆ {0..Suc k}" by blast
from A xs(1) ys(1) len_comp
have "fw m n (Suc k) i j i' j' = len m i' j' (xs @ Suc k # ys)" by simp
moreover have "set (xs @ Suc k # ys) ⊆ {0..Suc k}" using xs(2) ys(2) by auto
ultimately show ?thesis by blast
qed
qed
qed
lemma cycle_free_cycle_free_up_to:
"cycle_free m n ⟹ k ≤ n ⟹ cycle_free_up_to m k n"
unfolding cycle_free_def cycle_free_up_to_def by force
lemma cycle_free_diag:
"cycle_free m n ⟹ i ≤ n ⟹ 𝟭 ≤ m i i"
using cycle_free_up_to_diag[OF cycle_free_cycle_free_up_to] by blast
corollary fw_shortest_path:
"cycle_free m n ⟹ i' ≤ i ⟹ j' ≤ j ⟹ i ≤ n ⟹ j ≤ n ⟹ k ≤ n
⟹ D m i' j' k = fw m n k i j i' j'"
using fw_shortest_path_up_to[OF cycle_free_cycle_free_up_to] by auto
corollary fw_shortest:
assumes "cycle_free m n" "i ≤ n" "j ≤ n" "k ≤ n"
shows "fw m n n n n i j ≤ fw m n n n n i k + fw m n n n n k j"
proof (rule ccontr, goal_cases)
case 1
let ?S = "λ i j. {len m i j xs |xs. set xs ⊆ {0..n}}"
let ?FW = "fw m n n n n"
from assms fw_shortest_path
have FW: "?FW i j = D m i j n" "?FW i k = D m i k n" "?FW k j = D m k j n" by auto
with D_dest'' FW have "?FW i k ∈ ?S i k" "?FW k j ∈ ?S k j" by auto
then obtain xs ys where xs_ys:
"?FW i k = len m i k xs" "set xs ⊆ {0..n}" "?FW k j = len m k j ys" "set ys ⊆ {0..n}" by auto
let ?zs = "rem_cycles i j (xs @ k # ys)"
have *:"?FW i j = Min {len m i j xs |xs. set xs ⊆ {0..n} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
using FW(1) unfolding D_def .
have "set (xs @ k # ys) ⊆ {0..n}" using assms xs_ys by fastforce
from cycle_free_dest [OF ‹cycle_free m n› ‹i ≤ n› ‹j ≤ n› this]
have **:"len m i j ?zs ≤ len m i j (xs @ k # ys)" by auto
moreover have "i ∉ set ?zs" "j ∉ set ?zs" "distinct ?zs"
using rem_cycles_distinct remove_all_removes rem_cycles_removes_last by fast+
moreover have "set ?zs ⊆ {0..n}" using rem_cycles_subs[of i j"xs @ k # ys"] xs_ys assms by fastforce
ultimately have
"len m i j ?zs ∈ {len m i j xs |xs. set xs ⊆ {0..n} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}"
by blast
with * have "?FW i j ≤ len m i j ?zs" using D_base_finite'' by auto
with ** xs_ys len_comp 1 show ?case by auto
qed
section ‹Result Under the Presence of Negative Cycles›
lemma not_cylce_free_dest: "¬ cycle_free m n ⟹ ∃ k ≤ n. ¬ cycle_free_up_to m k n"
by (auto simp add: cycle_free_def cycle_free_up_to_def)
lemma D_not_diag_le:
"(x :: 'a) ∈ {len m i j xs |xs. set xs ⊆ {0..k} ∧ i ∉ set xs ∧ j ∉ set xs ∧ distinct xs}
⟹ D m i j k ≤ x" using Min_le[OF D_base_finite''] by (auto simp add: D_def)
lemma D_not_diag_le': "set xs ⊆ {0..k} ⟹ i ∉ set xs ⟹ j ∉ set xs ⟹ distinct xs
⟹ D m i j k ≤ len m i j xs" using Min_le[OF D_base_finite''] by (fastforce simp add: D_def)
lemma (in -) nat_upto_subs_top_removal':
"S ⊆ {0..Suc n} ⟹ Suc n ∉ S ⟹ S ⊆ {0..n}"
apply (induction n)
apply safe
apply (rename_tac x)
apply (case_tac "x = Suc 0"; fastforce)
apply (rename_tac n x)
apply (case_tac "x = Suc (Suc n)"; fastforce)
done
lemma (in -) nat_upto_subs_top_removal:
"S ⊆ {0..n::nat} ⟹ n ∉ S ⟹ S ⊆ {0..n - 1}"
using nat_upto_subs_top_removal' by (cases n; simp)
lemma fw_Suc:
"i ≤ n ⟹ j ≤ n ⟹ i' ≤ n ⟹ j' ≤ n ⟹ fw m n (Suc k) i' j' i j ≤ fw m n k n n i j"
by (metis Suc_innermost_id1' Suc_innermost_id2 Suc_innermost_mono linorder_class.not_le order.eq_iff
preorder_class.order_refl single_iteration_inv single_iteration_inv')
lemma negative_len_shortest:
"length xs = n ⟹ len m i i xs < 𝟭
⟹ ∃ j ys. distinct (j # ys) ∧ len m j j ys < 𝟭 ∧ j ∈ set (i # xs) ∧ set ys ⊆ set xs"
proof (induction n arbitrary: xs i rule: less_induct)
case (less n)
show ?case
proof (cases xs)
case Nil
thus ?thesis using less.prems by auto
next
case (Cons y ys)
then have "length xs ≥ 1" by auto
show ?thesis
proof (cases "i ∈ set xs")
assume i: "i ∈ set xs"
then obtain as bs where xs: "xs = as @ i # bs" by (meson split_list)
show ?thesis
proof (cases "len m i i as < 𝟭")
case True
from xs less.prems have "length as < n" by auto
from less.IH[OF this _ True] xs show ?thesis by auto
next
case False
from len_decomp[OF xs] have "len m i i xs = len m i i as + len m i i bs" by auto
with False less.prems have *: "len m i i bs < 𝟭"
by (metis add_lt_neutral local.dual_order.strict_trans local.neqE)
from xs less.prems have "length bs < n" by auto
from less.IH[OF this _ *] xs show ?thesis by auto
qed
next
assume i: "i ∉ set xs"
show ?thesis
proof (cases "distinct xs")
case True
with i less.prems show ?thesis by auto
next
case False
from not_distinct_decomp[OF this] obtain a as bs cs where xs:
"xs = as @ a # bs @ a # cs"
by auto
show ?thesis
proof (cases "len m a a bs < 𝟭")
case True
from xs less.prems have "length bs < n" by auto
from less.IH[OF this _ True] xs show ?thesis by auto
next
case False
from len_decomp[OF xs, of m i i] len_decomp[of "bs @ a # cs" bs a cs m a i]
have *:"len m i i xs = len m i a as + (len m a a bs + len m a i cs)" by auto
from False have "len m a a bs ≥ 𝟭" by auto
with add_mono have "len m a a bs + len m a i cs ≥ len m a i cs" by fastforce
with * have "len m i i xs ≥ len m i a as + len m a i cs" by (simp add: add_mono)
with less.prems(2) have "len m i a as + len m a i cs < 𝟭" by auto
with len_comp have "len m i i (as @ a # cs) < 𝟭" by auto
from less.IH[OF _ _ this, of "length (as @ a # cs)"] xs less.prems
show ?thesis by auto
qed
qed
qed
qed
qed
theorem FW_neg_cycle_detect:
"¬ cycle_free m n ⟹ ∃ i ≤ n. fw m n n n n i i < 𝟭"
proof -
assume A: "¬ cycle_free m n"
let ?K = "{k. k ≤ n ∧ ¬ cycle_free_up_to m k n}"
let ?k = "Min ?K"
have not_empty_K: "?K ≠ {}" using not_cylce_free_dest[OF A(1)] by auto
have "finite ?K" by auto
with not_empty_K have *:
"∀ k' < ?k. cycle_free_up_to m k' n"
by (auto, metis le_trans less_or_eq_imp_le preorder_class.less_irrefl)
from linorder_class.Min_in[OF ‹finite ?K› ‹?K ≠ {}›] have
"¬ cycle_free_up_to m ?k n" "?k ≤ n"
by auto
then have "∃ xs j. j ≤ n ∧ len m j j xs < 𝟭 ∧ set xs ⊆ {0..?k}" unfolding cycle_free_up_to_def
proof (auto, goal_cases)
case (2 i xs) then have "len m i i xs < 𝟭" by auto
with 2 show ?case by auto
next
case (1 i xs j)
then have "len m i j (rem_cycles i j xs) > len m i j xs" by auto
from negative_cycle_dest[OF this]
obtain i' ys where ys: "i' ∈ set (i # j # xs)" "len m i' i' ys < 𝟭" "set ys ⊆ set xs" by blast
from ys(1) 1(2-4) show ?case
proof (auto, goal_cases)
case 1
with ys(2,3) show ?case by auto
next
case 2
with ys(2,3) show ?case by auto
next
case 3
with ‹?k ≤ n› have "i' ≤ n" unfolding cycle_free_up_to_def by auto
with 3 ys(2,3) show ?case by auto
qed
qed
then obtain a as where a_as: "a ≤ n ∧ len m a a as < 𝟭 ∧ set as ⊆ {0..?k}" by auto
with negative_len_shortest[of as "length as" m a] obtain j xs where j_xs:
"distinct (j # xs) ∧ len m j j xs < 𝟭 ∧ j ∈ set (a # as) ∧ set xs ⊆ set as" by auto
with a_as ‹?k ≤ n› have cyc: "j ≤ n" "set xs ⊆ {0..?k}" "len m j j xs < 𝟭" "distinct (j # xs)"
by auto
{ assume "?k > 0"
then have "?k - 1 < ?k" by simp
with * have **:"cycle_free_up_to m (?k - 1) n" by blast
have "?k ∈ set xs"
proof (rule ccontr, goal_cases)
case 1
with ‹set xs ⊆ {0..?k}› nat_upto_subs_top_removal have "set xs ⊆ {0..?k-1}" by auto
from cycle_free_up_to_loop_dest[OF ‹j ≤ n› this ‹cycle_free_up_to m (?k - 1) n›] cyc(3)
show ?case by auto
qed
with cyc(4) have "j ≠ ?k" by auto
from ‹?k ∈ set xs› obtain ys zs where "xs = ys @ ?k # zs" by (meson split_list)
with ‹distinct (j # xs)›
have xs: "xs = ys @ ?k # zs" "distinct ys" "distinct zs" "?k ∉ set ys" "?k ∉ set zs"
"j ∉ set ys" "j ∉ set zs" by auto
from xs(1,4) ‹set xs ⊆ {0..?k}› nat_upto_subs_top_removal have ys: "set ys ⊆ {0..?k-1}" by auto
from xs(1,5) ‹set xs ⊆ {0..?k}› nat_upto_subs_top_removal have zs: "set zs ⊆ {0..?k-1}" by auto
have "D m j ?k (?k - 1) = fw m n (?k - 1) n n j ?k"
using ‹?k ≤ n› ‹j ≤ n› fw_shortest_path_up_to[OF **, of j n ?k n] by auto
moreover have "D m ?k j (?k - 1) = fw m n (?k - 1) n n ?k j"
using ‹?k ≤ n› ‹j ≤ n› fw_shortest_path_up_to[OF **, of ?k n j n] by auto
ultimately have "fw m n (?k - 1) n n j ?k + fw m n (?k - 1) n n ?k j ≤ len m j ?k ys + len m ?k j zs"
using D_not_diag_le'[OF zs(1) xs(5,7,3), of m]
D_not_diag_le'[OF ys(1) xs(6,4,2), of m] by (auto simp: add_mono)
then have neg: "fw m n (?k - 1) n n j ?k + fw m n (?k - 1) n n ?k j < 𝟭"
using xs(1) ‹len m j j xs < 𝟭› len_comp by auto
have "fw m n ?k j j j j ≤ fw m n (?k - 1) n n j ?k + fw m n (?k - 1) n n ?k j"
proof (cases "j = 0")
case True
with‹?k > 0› fw.simps(2)[of m n "?k - 1"]
have "fw m n ?k j j = fw_upd (fw m n (?k - 1) n n) ?k j j" by auto
then have "fw m n ?k j j j j ≤ fw m n (?k - 1) n n j ?k + fw m n (?k - 1) n n ?k j"
by (simp add: fw_upd_def upd_def)
then show ?thesis by auto
next
case False
with fw.simps(4)[of m n ?k j "j - 1"]
have "fw m n ?k j j = fw_upd (fw m n ?k j (j -1)) ?k j j" by simp
then have *: "fw m n ?k j j j j ≤ fw m n ?k j (j -1) j ?k + fw m n ?k j (j -1) ?k j"
by (simp add: fw_upd_def upd_def)
have "j - 1 < n" using ‹j ≤ n› False by auto
then have "fw m n ?k j (j -1) j ?k ≤ fw m n (?k - 1) n n j ?k"
using fw_Suc[of j n ?k j "j - 1" m "?k - 1"] ‹j ≤ n› ‹?k ≤ n› ‹?k > 0› by auto
moreover have "fw m n ?k j (j -1) ?k j ≤ fw m n (?k - 1) n n ?k j"
using fw_Suc[of ?k n j j "j - 1" m "?k - 1"] ‹j ≤ n› ‹?k ≤ n› ‹?k > 0› by auto
ultimately have "fw m n ?k j j j j ≤ fw m n (?k - 1) n n j ?k + fw m n (?k - 1) n n ?k j"
using * add_mono by fastforce
then show ?thesis by auto
qed
with neg have "fw m n ?k j j j j < 𝟭" by auto
moreover have "fw m n n n n j j ≤ fw m n ?k j j j j" using fw_invariant ‹j≤n› ‹?k ≤ n› by auto
ultimately have "fw m n n n n j j < 𝟭" using neg by auto
with ‹j≤n› have ?thesis by auto
}
moreover
{ assume "?k = 0"
with cyc(2,4) have "xs = [] ∨ xs = [0]"
apply safe
apply (case_tac xs)
apply fastforce
apply (rename_tac ys)
apply (case_tac ys)
apply auto
done
then have ?thesis
proof
assume "xs = []"
with cyc have "m j j < 𝟭" by auto
with fw_mono[of n n n j j m n] ‹j ≤ n› have "fw m n n n n j j < 𝟭" by auto
with ‹j ≤ n› show ?thesis by auto
next
assume xs: "xs = [0]"
with cyc have "m j 0 + m 0 j < 𝟭" by auto
then have "fw m n 0 j j j j < 𝟭"
proof (cases "j = 0", goal_cases)
case 1
have "m j j < 𝟭"
proof (rule ccontr)
assume "¬ m j j < 𝟭"
with 1 have "m 0 0 ≥ 𝟭" by simp
with add_mono have "m 0 0 + m 0 0 ≥ 𝟭" by fastforce
with 1 show False by simp
qed
with fw_mono[of j n j j j m 0] ‹j ≤ n› show ?thesis by auto
next
case 2
with fw.simps(4)[of m n 0 j "j - 1"]
have "fw m n 0 j j = fw_upd (fw m n 0 j (j - 1)) 0 j j" by simp
then have "fw m n 0 j j j j ≤ fw m n 0 j (j - 1) j 0 + fw m n 0 j (j - 1) 0 j"
by (simp add: fw_upd_def upd_def)
also have "… ≤ m j 0 + m 0 j" using ‹j ≤ n› add_mono fw_mono by auto
finally show ?thesis using 2 by auto
qed
then have "fw m n 0 n n j j < 𝟭" by (metis cyc(1) less_or_eq_imp_le single_iteration_inv)
with fw_invariant[of 0 n n n n n n m j j] ‹j ≤ n› have "fw m n n n n j j < 𝟭" by auto
with ‹j ≤ n› show ?thesis by blast
qed
}
ultimately show ?thesis by auto
qed
end
end