(* Use of this source code is governed by the license described	* * in the LICENSE file at the root of the source tree.		*)
Set Implicit Arguments.
Local Open Scope list_scope.
Inductive in_oc_supp : forall (A B C : Set), C -> OracleComp A B C -> Prop :=
| in_oc_supp_Bind :
forall (A B C C' : Set)(c : OracleComp A B C')(f : C' -> OracleComp A B C) x y,
in_oc_supp x c ->
in_oc_supp y (f x) ->
in_oc_supp y (OC_Bind c f)
| in_oc_supp_Query :
forall (A B : Set)(a : A)(b : B),
in_oc_supp b (OC_Query B a)
| in_oc_supp_Ret :
forall (A B C : Set)(c : Comp C) x,
In x (getSupport c) ->
in_oc_supp x (OC_Ret A B c)
| in_oc_supp_Run :
forall (A A' B B' C S : Set)(eqds : EqDec S)(eqda : EqDec A)(eqdb : EqDec B)
(c : OracleComp A B C)(oc : S -> A -> OracleComp A' B' (B * S)) s x s',
in_oc_supp x c ->
in_oc_supp (x, s') (OC_Run _ _ _ c oc s).
induction c; intuition; repeat simp_in_support.
econstructor.
Local Opaque getSupport.
simpl in *.
repeat simp_in_support.
destruct x.
simpl.
destruct p.
simpl.
econstructor.
eapply (@IHc _ _ (S * S0)%type).
eapply H1.
simpl in *.
repeat simp_in_support.
econstructor.
intuition.
assert (EqDec C).
eapply oc_EqDec.
eapply c.
intuition.
assert (B * S).
eapply comp_base_exists.
eapply o0.
trivial.
intuition.
intuition.
intuition.
assert (EqDec (B * S)).
eapply comp_EqDec.
eapply o0; trivial.
eapply EqDec_pair_l.
eapply H2.
trivial.
simpl in *.
repeat simp_in_support.
destruct x0.
econstructor.
eapply (@H0 _ S).
eapply H2.
eapply (@H _ _ _ S).
eapply H3.
Grab Existential Variables.
eapply EqDec_pair_l.
eauto.
trivial.
Qed.
Local Open Scope nat_scope.
Inductive queries_at_most' : forall (A B C : Set), OracleComp A B C -> nat -> Prop :=
| qam_Bind :
forall (A B C C' : Set)(eqdc' : EqDec C')(c : OracleComp A B C')(f : C' -> OracleComp A B C) q1 q2,
queries_at_most' c q1 ->
(forall c',
in_oc_supp c' c ->
queries_at_most' (f c') q2) ->
queries_at_most' (OC_Bind c f) (q1 + q2)
| qam_Query :
forall (A B : Set)(a : A),
queries_at_most' (OC_Query B a) 1
| qam_Ret :
forall (A B C : Set)(c : Comp C),
queries_at_most' (OC_Ret A B c) 0
| qam_Run :
forall (A A' B B' C S : Set)(eqds : EqDec S)(eqda : EqDec A)(eqdb : EqDec B)
(c : OracleComp A B C)(oc : S -> A -> OracleComp A' B' (B * S)) s q1 q2,
queries_at_most' c q1 ->
(forall s a, queries_at_most' (oc s a) q2) ->
queries_at_most' (OC_Run _ _ _ c oc s) (q1 * q2)
| qam_le :
forall (A B C : Set)(c : OracleComp A B C) q1 q2,
queries_at_most' c q1 ->
q1 <= q2 ->
queries_at_most' c q2.

Theorem qam_count_gen' :
forall (A B C : Set)(c : OracleComp A B C)(q : nat),
queries_at_most' c q ->
forall (S : Set)(count : S -> nat)(eqds : EqDec S)(o : S -> A -> Comp (B * S))(s : S)(n : nat),
(forall a b x y,
In (a, b) (getSupport (o x y)) ->
count b <= n + (count x)) ->
forall a b,
In (a, b) (getSupport (c _ _ o s)) ->
count b <= q * n + (count s).