(********************************************************************)
(*                                                                  *)
(*  The Why3 Verification Platform   /   The Why3 Development Team  *)
(*  Copyright 2010-2023 --  Inria - CNRS - Paris-Saclay University  *)
(*                                                                  *)
(*  This software is distributed under the terms of the GNU Lesser  *)
(*  General Public License version 2.1, with the special exception  *)
(*  on linking described in file LICENSE.                           *)
(*                                                                  *)
(********************************************************************)

(* This file is generated by Why3's Coq-realize driver *)
(* Beware! Only edit allowed sections below    *)
Require Import BuiltIn.
Require BuiltIn.
Require int.Int.
Require list.List.
Require list.Length.
Require list.Mem.
Require list.Append.
Require list.Reverse.

Require Import Lia.

(* Why3 goal *)
Definition num_occ {a:Type} {a_WT:WhyType a} :
  a -> Init.Datatypes.list a -> Numbers.BinNums.Z.
intros x.
exact (fix num_occ (l : list a) : int :=
  match l with
  | nil => 0
  | cons y r => (if why_decidable_eq x y then 1 else 0) + num_occ r
  end)%Z.
Defined.

(* Why3 goal *)
Lemma num_occ'def {a:Type} {a_WT:WhyType a} :
  forall (x:a) (l:Init.Datatypes.list a),
  match l with
  | Init.Datatypes.nil => ((num_occ x l) = 0%Z)
  | Init.Datatypes.cons y r =>
      ((x = y) -> ((num_occ x l) = (1%Z + (num_occ x r))%Z)) /\
      (~ (x = y) -> ((num_occ x l) = (0%Z + (num_occ x r))%Z))
  end.
Proof.
intros x [|y r].
easy.
split ; intros H.
change ((if why_decidable_eq x y then 1 else 0) + num_occ x r = 1 + num_occ x r)%Z.
now case why_decidable_eq.
change ((if why_decidable_eq x y then 1 else 0) + num_occ x r = 0 + num_occ x r)%Z.
now case why_decidable_eq.
Qed.

(* Why3 goal *)
Lemma Num_Occ_NonNeg {a:Type} {a_WT:WhyType a} :
  forall (x:a) (l:Init.Datatypes.list a), (0%Z <= (num_occ x l))%Z.
Proof.
intros x l.
induction l as [|lh lt IHl].
easy.
simpl.
case why_decidable_eq ; intros H.
lia.
easy.
Qed.

(* Why3 goal *)
Lemma Mem_Num_Occ {a:Type} {a_WT:WhyType a} :
  forall (x:a) (l:Init.Datatypes.list a),
  list.Mem.mem x l <-> (0%Z < (num_occ x l))%Z.
Proof.
intros x l.
induction l as [|lh lt IHl].
now split.
simpl.
case why_decidable_eq ; intros H ; split.
intros _.
clear.
generalize (Num_Occ_NonNeg x lt).
lia.
now left.
intros [H'|H'] ; try easy.
now apply IHl.
right.
now apply IHl.
Qed.

(* Why3 goal *)
Lemma Append_Num_Occ {a:Type} {a_WT:WhyType a} :
  forall (x:a) (l1:Init.Datatypes.list a) (l2:Init.Datatypes.list a),
  ((num_occ x (Init.Datatypes.app l1 l2)) =
   ((num_occ x l1) + (num_occ x l2))%Z).
Proof.
intros x l1 l2.
induction l1 as [|l1h l1t IHl1].
easy.
simpl.
rewrite IHl1.
rewrite Zplus_assoc.
now case why_decidable_eq.
Qed.

(* Why3 goal *)
Lemma reverse_num_occ {a:Type} {a_WT:WhyType a} :
  forall (x:a) (l:Init.Datatypes.list a),
  ((num_occ x l) = (num_occ x (Lists.List.rev l))).
intros x l.
induction l; simpl.
auto.
rewrite Append_Num_Occ.
rewrite <- IHl.
ring_simplify.
simpl (num_occ x (a0 :: nil))%list.
ring.
Qed.

