Require Import Bool Nat.

(** **** Exercise: 1 star, standard (nandb)

    The [Admitted] command can be used as a placeholder for an
    incomplete proof.  We use it in exercises to indicate the parts
    that we're leaving for you -- i.e., your job is to replace
    [Admitted]s with real proofs.

    Remove "[Admitted.]" below and complete the definition of the
    following function; then make sure that the [Example] assertions
    below can each be verified by Rocq.  (I.e., fill in each proof,
    following the model of the [orb] tests above, and make sure Rocq
    accepts it.) The function should return [true] if either or both
    of its inputs are [false].

    Hint: if [simpl] will not simplify the goal in your proof, it's
    probably because you defined [nandb] without using a [match]
    expression. Try a different definition of [nandb], or just skip
    over [simpl] and go directly to [reflexivity]. We'll explain
    what's happening later in the chapter. *)

Definition nandb (b1:bool) (b2:bool) : bool
  (* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted.

Example test_nandb1:               (nandb true false) = true.
(* FILL IN HERE *) Admitted.
Example test_nandb2:               (nandb false false) = true.
(* FILL IN HERE *) Admitted.
Example test_nandb3:               (nandb false true) = true.
(* FILL IN HERE *) Admitted.
Example test_nandb4:               (nandb true true) = false.
(* FILL IN HERE *) Admitted.

(** **** Exercise: 1 star, standard (norb) 
  Complete the definition of the norb function below, which should implement the
  nor operation, i.e., [norb a b] should be false when [a] or [b] is true and
  true otherwise. Write four Example tests that test the full truth table for nor,
  and make sure your definition passes them. If it doesn't, consider:
  is your function wrong, or is the test wrong?
*)

Definition norb (b1:bool) (b2:bool) : bool
  (* := ... *). Admitted.
(*
Example test_norb1:
Example test_norb2:
Example test_norb3:
Example test_norb4:
*)

(** **** Exercise: 1 star, standard (factorial)

    Recall the standard mathematical factorial function:

       factorial(0)  =  1
       factorial(n)  =  n * factorial(n-1)     (if n>0)

    Translate this into Rocq.

    Make sure you put a [:=] between the header we've provided and
    your definition.  If you see an error like "The reference
    factorial was not found in the current environment," it means
    you've forgotten the [:=]. *)

Fixpoint factorial (n:nat) : nat
  (* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted.

Example test_factorial1:          (factorial 3) = 6.
(* FILL IN HERE *) Admitted.
Example test_factorial2:          (factorial 5) = (mult 10 12).
(* FILL IN HERE *) Admitted.

(** **** Exercise: 1 star, standard (plus_id_exercise)

    Remove "[Admitted.]" and fill in the proof.  (Note that the
    theorem has _two_ hypotheses -- [n = m] and [m = o] -- each to the
    left of an implication arrow.) *)

Theorem plus_id_exercise : forall n m o : nat,
  n = m -> m = o -> n + m = m + o.
Proof.
  (* FILL IN HERE *) Admitted.

(** **** Exercise: 1 star, standard (zero_nbeq_plus_1) *)
Theorem zero_nbeq_plus_1 : forall n : nat,
  0 =? (n + 1) = false.
Proof.
  (* FILL IN HERE *) Admitted.

(** **** Exercise: 1 star, standard (identity_fn_applied_twice)

    Use the tactics you have learned so far to prove the following
    theorem about boolean functions. *)

Theorem identity_fn_applied_twice :
  forall (f : bool -> bool),
  (forall (x : bool), f x = x) ->
  forall (b : bool), f (f b) = b.
Proof.
  (* FILL IN HERE *) Admitted.

(** [] *)

(** **** Exercise: 1 star, standard (negation_fn_applied_twice)

    Now state and prove a theorem [negation_fn_applied_twice] similar
    to the previous one but where the second hypothesis says that the
    function [f] has the property that [f x = negb x]. *)

(* FILL IN HERE *)

(** Grad exercise (more_days) **)
(* The [day] type from Basics.v lists each day as a separate constructor: *)

Inductive day : Type :=
  | monday
  | tuesday
  | wednesday
  | thursday
  | friday
  | saturday
  | sunday.

(* Here is another representation of days, which explicitly separates
   weekdays and weekends: *)

Inductive weekday :=
| mon
| tue
| wed
| thu
| fri.

Inductive weekend :=
| sat
| sun.

Inductive day2 :=
| WD (d : weekday)
| WE (d : weekend).

(* The following function translates the [day] representation to [day2]: *)
Definition day_to_day2 (d : day) : day2 :=
  match d with
  | sunday => WE sun
  | monday => WD mon
  | tuesday => WD tue
  | wednesday => WD wed
  | thursday => WD thu
  | friday => WD fri
  | saturday => WE sat
  end.

(* Write a function day2_to_day that performs the opposite conversion. *)

(* State and prove a theorem saying that if we convert a day from [day] to
   [day2] and back, we get the same day we started with. *)
