Theory Simplex_for_Reals
section ‹Unsatisfiability over the Reals›
text ‹By using Farkas' Lemma we prove that a finite set of
linear rational inequalities is satisfiable over the rational numbers
if and only if it is satisfiable over the real numbers.
Hence, the simplex algorithm either gives a rational solution or
shows unsatisfiability over the real numbers.›
theory Simplex_for_Reals
imports
Farkas
Simplex.Simplex_Incremental
begin
instantiation real :: lrv
begin
definition scaleRat_real :: "rat ⇒ real ⇒ real" where
[simp]: "x *R y = real_of_rat x * y"
instance by standard (auto simp add: field_simps of_rat_mult of_rat_add)
end
abbreviation real_satisfies_constraints :: "real valuation ⇒ constraint set ⇒ bool" (infixl "⊨⇩r⇩c⇩s" 100) where
"v ⊨⇩r⇩c⇩s cs ≡ ∀ c ∈ cs. v ⊨⇩c c"
definition of_rat_val :: "rat valuation ⇒ real valuation" where
"of_rat_val v x = of_rat (v x)"
lemma of_rat_val_eval: "p ⦃of_rat_val v⦄ = of_rat (p ⦃v⦄)"
unfolding of_rat_val_def linear_poly_sum of_rat_sum
by (rule sum.cong, auto simp: of_rat_mult)
lemma of_rat_val_constraint: "of_rat_val v ⊨⇩c c ⟷ v ⊨⇩c c"
by (cases c, auto simp: of_rat_val_eval of_rat_less of_rat_less_eq)
lemma of_rat_val_constraints: "of_rat_val v ⊨⇩r⇩c⇩s cs ⟷ v ⊨⇩c⇩s cs"
using of_rat_val_constraint by auto
lemma sat_scale_rat_real: assumes "(v :: real valuation) ⊨⇩c c"
shows "v ⊨⇩c (r *R c)"
proof -
have "r < 0 ∨ r = 0 ∨ r > 0" by auto
then show ?thesis using assms by (cases c, simp_all add: right_diff_distrib
valuate_minus valuate_scaleRat scaleRat_leq1 scaleRat_leq2 valuate_zero
of_rat_less of_rat_mult)
qed
fun of_rat_lec :: "rat le_constraint ⇒ real le_constraint" where
"of_rat_lec (Le_Constraint r p c) = Le_Constraint r p (of_rat c)"
lemma lec_of_constraint_real:
assumes "is_le c"
shows "(v ⊨⇩l⇩e of_rat_lec (lec_of_constraint c)) ⟷ (v ⊨⇩c c)"
using assms by (cases c, auto)
lemma of_rat_lec_add: "of_rat_lec (c + d) = of_rat_lec c + of_rat_lec d"
by (cases c; cases d, auto simp: of_rat_add)
lemma of_rat_lec_zero: "of_rat_lec 0 = 0"
unfolding zero_le_constraint_def by simp
lemma of_rat_lec_sum: "of_rat_lec (sum_list c) = sum_list (map of_rat_lec c)"
by (induct c, auto simp: of_rat_lec_zero of_rat_lec_add)
text ‹This is the main lemma: a finite set of linear constraints is
satisfiable over Q if and only if it is satisfiable over R.›
lemma rat_real_conversion: assumes "finite cs"
shows "(∃ v :: rat valuation. v ⊨⇩c⇩s cs) ⟷ (∃ v :: real valuation. v ⊨⇩r⇩c⇩s cs)"
proof
show "∃v. v ⊨⇩c⇩s cs ⟹ ∃v. v ⊨⇩r⇩c⇩s cs" using of_rat_val_constraint by auto
assume "∃v. v ⊨⇩r⇩c⇩s cs"
then obtain v where *: "v ⊨⇩r⇩c⇩s cs" by auto
show "∃v. v ⊨⇩c⇩s cs"
proof (rule ccontr)
assume "∄v. v ⊨⇩c⇩s cs"
from farkas_coefficients[OF assms] this
obtain C where "farkas_coefficients cs C" by auto
from this[unfolded farkas_coefficients_def]
obtain d rel where
isleq: "(∀(r,c) ∈ set C. c ∈ cs ∧ is_le (r *R c) ∧ r ≠ 0)" and
leq: "(∑ (r,c) ← C. lec_of_constraint (r *R c)) = Le_Constraint rel 0 d" and
choice: "rel = Lt_Rel ∧ d ≤ 0 ∨ rel = Leq_Rel ∧ d < 0" by blast
{
fix r c
assume c: "(r,c) ∈ set C"
from c * isleq have "v ⊨⇩c c" by auto
hence v: "v ⊨⇩c (r *R c)" by (rule sat_scale_rat_real)
from c isleq have "is_le (r *R c)" by auto
from lec_of_constraint_real[OF this] v
have "v ⊨⇩l⇩e of_rat_lec (lec_of_constraint (r *R c))" by blast
} note v = this
have "Le_Constraint rel 0 (of_rat d) = of_rat_lec (∑ (r,c) ← C. lec_of_constraint (r *R c))"
unfolding leq by simp
also have "… = (∑ (r,c) ← C. of_rat_lec (lec_of_constraint (r *R c)))" (is "_ = ?sum")
unfolding of_rat_lec_sum map_map o_def by (rule arg_cong[of _ _ sum_list], auto)
finally have leq: "Le_Constraint rel 0 (of_rat d) = ?sum" by simp
have "v ⊨⇩l⇩e Le_Constraint rel 0 (of_rat d)" unfolding leq
by (rule satisfies_sumlist_le_constraints, insert v, auto)
with choice show False by (auto simp: linear_poly_sum)
qed
qed
text ‹The main result of simplex, now using unsatisfiability over the reals.›
fun i_satisfies_cs_real (infixl "⊨⇩r⇩i⇩c⇩s" 100) where
"(I,v) ⊨⇩r⇩i⇩c⇩s cs ⟷ v ⊨⇩r⇩c⇩s Simplex.restrict_to I cs"
lemma simplex_index_real:
"simplex_index cs = Unsat I ⟹ set I ⊆ fst ` set cs ∧ ¬ (∃ v. (set I, v) ⊨⇩r⇩i⇩c⇩s set cs) ∧
(distinct_indices cs ⟶ (∀ J ⊂ set I. (∃ v. (J, v) ⊨⇩i⇩c⇩s set cs)))"
"simplex_index cs = Sat v ⟹ ⟨v⟩ ⊨⇩c⇩s (snd ` set cs)"
using simplex_index(1)[of cs I] simplex_index(2)[of cs v]
rat_real_conversion[of "Simplex.restrict_to (set I) (set cs)"]
by auto
lemma simplex_real:
"simplex cs = Unsat I ⟹ ¬ (∃ v. v ⊨⇩r⇩c⇩s set cs)"
"simplex cs = Unsat I ⟹ set I ⊆ {0..<length cs} ∧ ¬ (∃ v. v ⊨⇩r⇩c⇩s {cs ! i | i. i ∈ set I})
∧ (∀J⊂set I. ∃v. v ⊨⇩c⇩s {cs ! i |i. i ∈ J})"
"simplex cs = Sat v ⟹ ⟨v⟩ ⊨⇩c⇩s set cs"
proof (intro simplex(1)[unfolded rat_real_conversion[OF finite_set]])
assume unsat: "simplex cs = Inl I"
have "finite {cs ! i |i. i ∈ set I}" by auto
from simplex(2)[OF unsat, unfolded rat_real_conversion[OF this]]
show "set I ⊆ {0..<length cs} ∧ ¬ (∃ v. v ⊨⇩r⇩c⇩s {cs ! i | i. i ∈ set I})
∧ (∀J⊂set I. ∃v. v ⊨⇩c⇩s {cs ! i |i. i ∈ J})" by auto
qed (insert simplex(3), auto)
text ‹Define notion of minimal unsat core over the reals:
the subset has to be unsat over the reals, and every proper subset has
to be satisfiable over the rational numbers.›
definition minimal_unsat_core_real :: "'i set ⇒ 'i i_constraint list ⇒ bool" where
"minimal_unsat_core_real I ics = ((I ⊆ fst ` set ics) ∧ (¬ (∃ v. (I,v) ⊨⇩r⇩i⇩c⇩s set ics))
∧ (distinct_indices ics ⟶ (∀ J. J ⊂ I ⟶ (∃ v. (J,v) ⊨⇩i⇩c⇩s set ics))))"
text ‹Because of equi-satisfiability the two notions of minimal unsat cores coincide.›
lemma minimal_unsat_core_real_conv: "minimal_unsat_core_real I ics = minimal_unsat_core I ics"
proof
show "minimal_unsat_core_real I ics ⟹ minimal_unsat_core I ics"
unfolding minimal_unsat_core_real_def minimal_unsat_core_def
using of_rat_val_constraint by simp metis
next
assume "minimal_unsat_core I ics"
thus "minimal_unsat_core_real I ics"
unfolding minimal_unsat_core_real_def minimal_unsat_core_def
using rat_real_conversion[of "Simplex.restrict_to I (set ics)"]
by auto
qed
text ‹Easy consequence: The incremental simplex algorithm is also sound wrt.
minimal-unsat-cores over the reals.›
lemmas incremental_simplex_real =
init_simplex
assert_simplex_ok
assert_simplex_unsat[folded minimal_unsat_core_real_conv]
assert_all_simplex_ok
assert_all_simplex_unsat[folded minimal_unsat_core_real_conv]
check_simplex_ok
check_simplex_unsat[folded minimal_unsat_core_real_conv]
solution_simplex
backtrack_simplex
checked_invariant_simplex
end