Require Export Lia Arith Ring.
From Undecidability.Shared.Libs.PSL Require FinTypes.
Record leUpToC {X} (f g : X -> nat) : Type :=
{ c__leUpToC : nat;
correct__leUpToC : forall x, f x <= c__leUpToC * g x
}.
Arguments c__leUpToC {_ _ _ H} : rename.
Notation "f <=c g" := (@leUpToC _ f g) (at level 70, g at next level).
Instance leUpToC_preorder X: PreOrder (@leUpToC X).
Instance leUpToC_proper_eq X: Proper (Morphisms.pointwise_relation X eq ==> Morphisms.pointwise_relation X eq ==> arrow) (@leUpToC X).
Instance leUpToC_proper_eq_flip X: Proper (Morphisms.pointwise_relation X eq ==> Morphisms.pointwise_relation X eq ==> flip arrow) (@leUpToC X).
Instance le_leUpToC_subrelation X: subrelation (pointwise_relation X le) leUpToC.
Instance eq_leUpToC_subrelation X: subrelation (pointwise_relation X eq) leUpToC.
(* A record for easily expressing the subtype of functions up to some multiplicative constant. *)
Record UpToC {X} (F : X -> nat) : Type :=
mkUpToC
{
f__UpToC :> X -> nat;
correct__UpToC :> f__UpToC <=c F
}.
Add Printing Coercion f__UpToC.
Arguments f__UpToC : clear implicits.
Arguments f__UpToC {_} _ {_}.
destruct f as [? []];cbn. easy.
Qed.
Tactic Notation  "_applyIfNotConst_nat" tactic(t):=
once (match goal with
| |- ?R (fun x => ?c) _ =>  tryif let b := isnatcst c in unify b true then fail 1 else t
end).

Lemma upToC_le X f (F : X -> nat):
(forall x, f x <= F x)
-> f <=c F.