(* ========================================================================= *)
(* Simple universal variant of Bob Solovay's procedure for vector spaces. *)
(* ========================================================================= *)
needs "Multivariate/misc.ml";;
needs "Multivariate/vectors.ml";;
(* ------------------------------------------------------------------------- *)
(* Initial simplification so we just use dot products between vectors. *)
(* ------------------------------------------------------------------------- *)
let NORM_ELIM_CONV =
let dest_norm tm =
let nm,v = dest_comb tm in
if fst(dest_const nm) <> "vector_norm" then failwith "dest_norm"
else v in
let is_norm = can dest_norm in
fun tm ->
let t = find_term (fun t -> is_norm t & free_in t tm) tm in
let v = dest_norm t in
let w = genvar(type_of t) in
let th1 = ISPECL [mk_abs(w,subst[w,t] tm); v] NORM_ELIM_THM in
CONV_RULE(COMB2_CONV (RAND_CONV BETA_CONV)
(BINDER_CONV(RAND_CONV BETA_CONV))) th1;;
let NORM_ELIM_TAC =
CONV_TAC NORM_ELIM_CONV THEN GEN_TAC;;
let SOLOVAY_TAC =
REWRITE_TAC[orthogonal; GSYM DOT_EQ_0] THEN
REWRITE_TAC[VECTOR_EQ] THEN
REWRITE_TAC[VECTOR_SUB_ELIM_THM] THEN
REWRITE_TAC[NORM_EQ; NORM_LE; NORM_LT; real_gt; real_ge] THEN
REPEAT NORM_ELIM_TAC THEN
REWRITE_TAC[DOT_LADD; DOT_RADD; DOT_LMUL; DOT_RMUL];;
(* ------------------------------------------------------------------------- *)
(* Iterative Gram-Schmidt type process. *)
(* ------------------------------------------------------------------------- *)
let GRAM_SCHMIDT_LEMMA = prove
(`!w:real^N vs. ?u as.
ALL (orthogonal u) vs /\ (
LENGTH as =
LENGTH vs) /\
(w =
ITLIST2 (\a v s. a % v + s) as vs u)`,
ONCE_REWRITE_TAC[
SWAP_FORALL_THM] THEN MATCH_MP_TAC
list_INDUCT THEN
SIMP_TAC[
ALL;
LENGTH;
ITLIST2;
LENGTH_EQ_NIL] THEN CONJ_TAC THENL
[X_GEN_TAC `w:real^N` THEN EXISTS_TAC `w:real^N` THEN
EXISTS_TAC `[]:real list` THEN REWRITE_TAC[
ITLIST2];
ALL_TAC] THEN
MAP_EVERY X_GEN_TAC [`v:real^N`; `vs:(real^N)list`] THEN
REWRITE_TAC[
LENGTH_EQ_CONS] THEN DISCH_TAC THEN X_GEN_TAC `w:real^N` THEN
FIRST_X_ASSUM(fun th ->
MP_TAC(SPEC `w:real^N` th) THEN MP_TAC(SPEC `v:real^N` th)) THEN
DISCH_THEN(X_CHOOSE_THEN `z:real^N` (X_CHOOSE_THEN `cs:real list`
(STRIP_ASSUME_TAC o GSYM))) THEN
DISCH_THEN(X_CHOOSE_THEN `u:real^N` (X_CHOOSE_THEN `as:real list`
(STRIP_ASSUME_TAC o GSYM))) THEN
MP_TAC(ISPECL [`z:real^N`; `u:real^N`]
COMPONENT_ORTHOGONAL) THEN
ABBREV_TAC `k = component z (u:real^N)` THEN
ABBREV_TAC `x = u - k % z :real^N` THEN DISCH_TAC THEN
MAP_EVERY EXISTS_TAC
[`x:real^N`; `CONS k (
MAP2 (\a c. a - k * c) as cs)`] THEN
REWRITE_TAC[
CONS_11;
RIGHT_EXISTS_AND_THM; GSYM
CONJ_ASSOC;
UNWIND_THM1] THEN
SUBGOAL_THEN `
ALL (orthogonal(x:real^N)) vs` ASSUME_TAC THENL
[UNDISCH_TAC `
ALL (orthogonal(z:real^N)) vs` THEN
UNDISCH_TAC `
ALL (orthogonal(u:real^N)) vs` THEN
REWRITE_TAC[IMP_IMP;
AND_ALL] THEN
MATCH_MP_TAC
MONO_ALL THEN REWRITE_TAC[] THEN
EXPAND_TAC "x" THEN SIMP_TAC[
ORTHOGONAL_CLAUSES];
ALL_TAC] THEN
REPEAT CONJ_TAC THENL
[EXPAND_TAC "v" THEN MATCH_MP_TAC
ORTHOGONAL_SUM_LEMMA THEN
ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[
ORTHOGONAL_SYM];
FIRST_ASSUM ACCEPT_TAC;
ASM_MESON_TAC[
LENGTH_MAP2];
ALL_TAC] THEN
REWRITE_TAC[
ITLIST2; VECTOR_ARITH `(a = b + c:real^N) = (c = a - b)`] THEN
MAP_EVERY EXPAND_TAC ["v";
"w"; "x"] THEN
UNDISCH_TAC `LENGTH(vs:(real^N)list) = LENGTH(cs:real list)` THEN
UNDISCH_TAC `LENGTH(vs:(real^N)list) = LENGTH(as:real list)` THEN
REWRITE_TAC[IMP_CONJ] THEN
MAP_EVERY (fun v -> SPEC_TAC(v,v))
[`vs:(real^N)list`; `cs:real list`; `as:real list`] THEN
POP_ASSUM_LIST(K ALL_TAC) THEN
LIST_INDUCT_TAC THEN LIST_INDUCT_TAC THEN LIST_INDUCT_TAC THEN
REWRITE_TAC[NOT_CONS_NIL; NOT_SUC; ITLIST2; LENGTH; ALL; SUC_INJ; MAP2] THEN
ASM_SIMP_TAC[] THEN REPEAT DISCH_TAC THEN VECTOR_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Hence this is a simple equality. *)
(* ------------------------------------------------------------------------- *)
let SOLOVAY_LEMMA = prove
(`!P vs. (!w:real^N. P w vs) =
(!as u.
ALL (orthogonal u) vs /\ (
LENGTH as =
LENGTH vs)
==> P (
ITLIST2 (\a v s. a % v + s) as vs u) vs)`,
REPEAT GEN_TAC THEN EQ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN DISCH_TAC THEN
X_GEN_TAC `w:real^N` THEN
MP_TAC(ISPECL [`w:real^N`; `vs:(real^N)list`]
GRAM_SCHMIDT_LEMMA) THEN
ASM_MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Set up the specific instances to get rid of list stuff. *)
(* ------------------------------------------------------------------------- *)
let ORTHOGONAL_SIMP_CLAUSES = prove
(`orthogonal u x
==> (u dot x = &0) /\ (x dot u = &0) /\
(u dot (a % x) = &0) /\ ((a % x) dot u = &0) /\
(u dot (a % x + y) = u dot y) /\ ((a % x + y) dot u = y dot u) /\
(u dot (y + a % x) = u dot y) /\ ((y + a % x) dot u = y dot u)`,
(* ------------------------------------------------------------------------- *)
(* A nicer proforma version. *)
(* ------------------------------------------------------------------------- *)
let SOLOVAY_PROFORMA_EQ = prove
(`(!w:real^N. P (
MAP ((dot) w) (CONS w vs)) vs) =
(!u.
ALL (orthogonal u) vs
==> !as. (
LENGTH as =
LENGTH vs)
==> P (CONS
((
ITLIST2 (\a v s. a % v + s) as vs (vec 0)) dot
(
ITLIST2 (\a v s. a % v + s) as vs (vec 0)) +
u dot u)
(
MAP ((dot)
(
ITLIST2 (\a v s. a % v + s) as vs (vec 0)))
vs))
vs)`,
MP_TAC(ISPEC `\w:real^N vs. P (
MAP ((dot) w) (CONS w vs)) vs :bool`
SOLOVAY_LEMMA) THEN
REWRITE_TAC[] THEN
DISCH_THEN(fun th -> GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [th]) THEN
GEN_REWRITE_TAC LAND_CONV [
SWAP_FORALL_THM] THEN
AP_TERM_TAC THEN GEN_REWRITE_TAC I [
FUN_EQ_THM] THEN
X_GEN_TAC `u:real^N` THEN REWRITE_TAC[] THEN
REWRITE_TAC[
RIGHT_IMP_FORALL_THM] THEN
AP_TERM_TAC THEN GEN_REWRITE_TAC I [
FUN_EQ_THM] THEN
X_GEN_TAC `as:(real)list` THEN REWRITE_TAC[IMP_IMP] THEN
MATCH_MP_TAC(TAUT `(a ==> (b = c)) ==> (a ==> b <=> a ==> c)`) THEN
STRIP_TAC THEN REWRITE_TAC[
MAP] THEN BINOP_TAC THEN
REWRITE_TAC[
CONS_11] THEN ONCE_REWRITE_TAC[
ITLIST2_0_LEMMA] THEN
REWRITE_TAC[
VECTOR_ADD_RID] THEN
REWRITE_TAC[VECTOR_ARITH
`(a + u) dot (a + u) = a dot a + &2 * (u dot a) + u dot u`] THEN
REWRITE_TAC[REAL_ARITH `(a + &2 * b + c = a + c) <=> (b = &0)`] THEN
GEN_REWRITE_TAC (RAND_CONV o BINOP_CONV o LAND_CONV) [GSYM ETA_AX] THEN
REWRITE_TAC[
DOT_LADD] THEN CONJ_TAC THENL
[POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN
SPEC_TAC(`vs:(real^N)list`,`vs:(real^N)list`) THEN
SPEC_TAC(`as:(real)list`,`as:(real)list`) THEN
REPEAT LIST_INDUCT_TAC THEN REWRITE_TAC[
LENGTH;
NOT_SUC] THEN
REWRITE_TAC[
ALL;
ITLIST2;
DOT_RZERO;
SUC_INJ] THEN
ASM_SIMP_TAC[
DOT_RADD] THEN
REWRITE_TAC[
REAL_ADD_RID;
DOT_RMUL] THEN
SIMP_TAC[orthogonal] THEN REWRITE_TAC[
REAL_MUL_RZERO];
MATCH_MP_TAC
MAP_EQ THEN
REWRITE_TAC[REAL_ARITH `(a + b = a) <=> (b = &0)`] THEN
MATCH_MP_TAC
ALL_IMP THEN EXISTS_TAC `orthogonal (u:real^N)` THEN
ASM_REWRITE_TAC[] THEN SIMP_TAC[orthogonal]]);;
(* ------------------------------------------------------------------------- *)
(* The implication that we normally use. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Automatically set up an implication for n (+1 eliminated) quantifier. *)
(* ------------------------------------------------------------------------- *)
let SOLOVAY_RULE =
let v_tm = `v:(real^N)list` and d_tm = `d:real list`
and elv_tm = `EL:num->(real^N)list->real^N`
and eld_tm = `EL:num->(real)list->real`
and rn_ty = `:real^N`
and rewr_rule = REWRITE_RULE
[MAP; EL; HD; TL; LENGTH; FORALL_LENGTH_CLAUSES;
ITLIST2; VECTOR_ADD_RID; VECTOR_ADD_LID; DOT_LZERO]
and sewr_rule = PURE_ONCE_REWRITE_RULE[DOT_SYM] in
fun n ->
let args =
map (fun i -> mk_comb(mk_comb(elv_tm,mk_small_numeral i),v_tm))
(0--(n-1)) @
map (fun i -> mk_comb(mk_comb(eld_tm,mk_small_numeral i),d_tm))
(1--n) @
[mk_comb(mk_comb(eld_tm,mk_small_numeral 0),d_tm)] in
let pty = itlist (mk_fun_ty o type_of) args bool_ty in
let p_tm = list_mk_abs([d_tm;v_tm],list_mk_comb(mk_var("P",pty),args))
and vs = make_args "v" [] (replicate rn_ty n) in
let th1 = ISPECL [p_tm; mk_list(vs,rn_ty)] SOLOVAY_PROFORMA in
let th2 = rewr_rule(CONV_RULE(TOP_DEPTH_CONV num_CONV) th1) in
let th3 = sewr_rule th2 in
itlist (fun v -> MATCH_MP MONO_FORALL o GEN v) vs th3;;
(* ------------------------------------------------------------------------- *)
(* Now instantiate it to some special cases. *)
(* ------------------------------------------------------------------------- *)
let MK_SOLOVAY_PROFORMA =
let preths = map SOLOVAY_RULE (0--9) in
fun n -> if n < 10 then el n preths else SOLOVAY_RULE n;;
(* ------------------------------------------------------------------------- *)
(* Apply it to a goal. *)
(* ------------------------------------------------------------------------- *)
let is_vector_ty ty =
match ty with
Tyapp("cart",[Tyapp("real",[]);_]) -> true
| _ -> false;;
let SOLOVAY_REDUCE_TAC (asl,w) =
let avs = sort (<) (filter (is_vector_ty o type_of) (frees w)) in
(REWRITE_TAC[DOT_SYM] THEN
MAP_EVERY (fun v -> SPEC_TAC(v,v)) (rev avs) THEN
MATCH_MP_TAC(MK_SOLOVAY_PROFORMA (length avs - 1)) THEN
REWRITE_TAC[DOT_LADD; DOT_LMUL; DOT_RADD; DOT_RMUL; DOT_LZERO;
DOT_RZERO] THEN
REPEAT GEN_TAC) (asl,w);;
(* ------------------------------------------------------------------------- *)
(* Overall tactic. *)
(* ------------------------------------------------------------------------- *)
let SOLOVAY_VECTOR_TAC =
REWRITE_TAC[dist; real_gt; real_ge; NORM_LT; NORM_LE; GSYM DOT_POS_LT] THEN
REPEAT GEN_TAC THEN SOLOVAY_TAC THEN
REWRITE_TAC[DOT_LZERO; DOT_RZERO] THEN
REPEAT SOLOVAY_REDUCE_TAC THEN
REWRITE_TAC[REAL_MUL_LZERO; REAL_MUL_RZERO; REAL_MUL_LID; REAL_MUL_RID;
REAL_ADD_LID; REAL_ADD_RID] THEN
REWRITE_TAC[IMP_IMP; RIGHT_IMP_FORALL_THM; GSYM CONJ_ASSOC] THEN
REPEAT GEN_TAC THEN
REWRITE_TAC[REAL_MUL_LNEG; REAL_MUL_RNEG; REAL_NEG_NEG;
REAL_MUL_LID; REAL_MUL_RID; GSYM real_sub];;
(* ------------------------------------------------------------------------- *)
(* An example where REAL_RING then works. *)
(* ------------------------------------------------------------------------- *)
let PYTHAGORAS = prove
(`!A B C:real^N.
orthogonal (A - B) (C - B)
==> norm(C - A) pow 2 = norm(B - A) pow 2 + norm(C - B) pow 2`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_RING);;
(*** Actually in this case we can fairly easily do things manually, though
we do need to explicitly use symmetry of the dot product.
let PYTHAGORAS = prove
(`!A B C:real^N.
orthogonal (A - B) (C - B)
==> norm(C - A) pow 2 = norm(B - A) pow 2 + norm(C - B) pow 2`,
REWRITE_TAC[NORM_POW_2; orthogonal; DOT_LSUB; DOT_RSUB; DOT_SYM] THEN
CONV_TAC REAL_RING);;
***)
(* ------------------------------------------------------------------------- *)
(* Examples. *)
(* ------------------------------------------------------------------------- *)
needs "Examples/sos.ml";;
let EXAMPLE_1 = prove
(`!x y:real^N. x dot y <= norm x * norm y`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
let EXAMPLE_2 = prove
(`!x y:real^N. a % (x + y) = a % x + a % y`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
(*** Takes a few minutes but does work
let EXAMPLE_3 = prove
(`!x y:real^N. norm (x + y) <= norm x + norm y`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
****)
let EXAMPLE_4 = prove
(`!x y z. x dot (y + z) = (x dot y) + (x dot z)`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
let EXAMPLE_5 = prove
(`!x y. (x dot x = &0) ==> (x dot y = &0)`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
(* ------------------------------------------------------------------------- *)
(* This is NORM_INCREASES_ONLINE. *)
(* ------------------------------------------------------------------------- *)
g `!a d:real^N.
~(d = vec 0) ==> norm (a + d) > norm a \/ norm (a - d) > norm a`;;
time e SOLOVAY_VECTOR_TAC;;
time e (CONV_TAC REAL_SOS);;
(* ------------------------------------------------------------------------- *)
(* DIST_INCREASES_ONLINE *)
(* ------------------------------------------------------------------------- *)
g `!b a d:real^N.
~(d = vec 0) ==> dist(a,b + d) > dist(a,b) \/ dist(a,b - d) > dist(a,b)`;;
time e SOLOVAY_VECTOR_TAC;;
time e (CONV_TAC REAL_SOS);;
(* ------------------------------------------------------------------------- *)
(* This one doesn't seem to work easily, but I think it does eventually. *)
(* ------------------------------------------------------------------------- *)
(****
let EXAMPLE_6 = prove
(`!a x. norm(a % x) = abs(a) * norm x`;;
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
****)
let EXAMPLE_7 = prove
(`!x. abs(norm x) = norm x`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
(*** But this is (at least) really slow
let EXAMPLE_8 = prove
(`!x y. abs(norm(x) - norm(y)) <= abs(norm(x - y))`,
SOLOVAY_VECTOR_TAC THEN CONV_TAC REAL_SOS);;
****)
(* ------------------------------------------------------------------------- *)
(* One from separating hyperplanes with a richer structure. *)
(* ------------------------------------------------------------------------- *)
needs "Rqe/make.ml";;
let EXAMPLE_9 = prove
(`!x:real^N y. x dot y > &0 ==> ?u. &0 < u /\ norm(u % y - x) < norm x`,
SOLOVAY_VECTOR_TAC THEN
W(fun (asl,w) -> MAP_EVERY (fun v -> SPEC_TAC(v,v)) (frees w)) THEN
CONV_TAC REAL_QELIM_CONV);;
(* ------------------------------------------------------------------------- *)
(* Even richer set of quantifier alternations. *)
(* ------------------------------------------------------------------------- *)
let EXAMPLE_10 = prove
(`!x:real^N y.
x dot y > &0
==> ?u. &0 < u /\
!v. &0 < v /\ v <= u ==> norm(v % y - x) < norm x`,
SOLOVAY_VECTOR_TAC THEN
W(fun (asl,w) -> MAP_EVERY (fun v -> SPEC_TAC(v,v)) (frees w)) THEN
CONV_TAC REAL_QELIM_CONV);;