Ltac inv H := 
inversion H; 
clear H; 
subst.
Ltac cases :=
  
repeat match goal with
         | 
H: 
context [ 
match negb ?
x with _ => _ 
end ] |- _ =>
           
destruct x; 
simpl; 
try solve [
inv H; 
auto]
         | 
H: 
context [ 
match ?
x with _ => _ 
end ] |- _ =>
           
destruct x; 
try solve [
inv H; 
auto]
         | |- 
context [ 
match negb ?
x with _ => _ 
end ] =>
           
destruct x; 
simpl
         | |- 
context [ 
match ?
x with _ => _ 
end ] =>
           
destruct x
         end; 
auto.
Ltac cases_eqn E :=
  
repeat match goal with
         | 
H: 
context [ 
match negb ?
x with _ => _ 
end ] |- _ =>
           
let E := 
fresh E in
           destruct x eqn: 
E; 
simpl; 
try solve [
inv H; 
auto]
         | 
H: 
context [ 
match ?
x with _ => _ 
end ] |- _ =>
           
let E := 
fresh E in
           destruct x eqn: 
E; 
try solve [
inv H; 
auto]
         | |- 
context [ 
match negb ?
x with _ => _ 
end ] =>
           
let E := 
fresh E in
           destruct x eqn: 
E; 
simpl
         | |- 
context [ 
match ?
x with _ => _ 
end ] =>
           
let E := 
fresh E in
           destruct x eqn: 
E
         end; 
auto.
Ltac cases_in H :=
  
repeat match type of H with
         | 
context [ 
match negb ?
x with _ => _ 
end ] =>
           
destruct x; 
simpl; 
try solve [
inv H; 
auto]
         | 
context [ 
match ?
x with _ => _ 
end ] =>
           
destruct x; 
try solve [
inv H; 
auto]
         
end; 
auto.
Create HintDb conjs.
Ltac destruct_conjs :=
  
autounfold with conjs in *;
  
repeat
    match goal with
    | 
H: 
exists _, _ |- _ => 
destruct H
    | 
H: _ /\ _ |- _ => 
destruct H
    | 
x: _ * _ |- _ => 
destruct x
    end; 
simpl in *.
Lemma option_map_inv:
  
forall {
A B} (
f: 
A -> 
B) 
oa b,
    
option_map f oa = 
Some b ->
    
exists a, 
oa = 
Some a /\ 
b = 
f a.
Proof.
  unfold option_map; 
intros * 
E.
  
cases; 
inv E; 
eauto.
Qed.
  
Lemma option_map_None:
  
forall {
A B} (
f: 
A -> 
B) 
oa,
    
option_map f oa = 
None <-> 
oa = 
None.
Proof.
  unfold option_map; 
intros; 
cases; 
intuition; 
discriminate.
Qed.
  
Ltac inv_equalities :=
  
destruct_conjs; 
subst;
  
repeat
    match goal with
    | 
H: (_, _) = (_, _) |- _ => 
inv H
    | 
H: 
option_map _ _ = 
Some _ |- _ =>
        
let Hf := 
fresh "Hf" in
        let Heq := 
fresh "Heq" in
        apply option_map_inv in H as (?&
Hf&
Heq); 
destruct_conjs
    | 
H: 
option_map _ _ = 
None |- _ =>
        
apply option_map_None in H
    end; 
subst.
Tactic Notation "summon" uconstr(
ty) 
"as" ident(
id) :=
  
match goal with H : _ |- _ => 
pose (
id := 
H : 
ty); 
clear id; 
rename H into id end.
Tactic Notation "take" uconstr(
ty) 
"and" tactic(
tac) :=
  
let new_it := 
fresh "it"
  in try (
rename it into new_it);
     
summon ty as it; 
tac;
     
try (
rename new_it into it).
Tactic Notation "take" uconstr(
ty1) 
"," uconstr(
ty2) 
"and" tactic(
tac) :=
  
let it1 := 
fresh "it1" in
  let it2 := 
fresh "it2" in
  summon ty1 as it1; 
summon ty2 as it2; 
tac.