Commit 482e34a8 authored by Nikita Zyuzin's avatar Nikita Zyuzin

Prove validErrorBoundsCmd from soundness of validErrorboundAA_sound

parent 97e83312
......@@ -130,3 +130,17 @@ Proof.
- eapply IHf; eauto.
- eapply Gamma_det; eauto.
Qed.
Lemma bstep_det f:
forall E Gamma DeltaMap v1 v2 m,
bstep f E Gamma DeltaMap v1 m ->
bstep f E Gamma DeltaMap v2 m ->
v1 = v2.
Proof.
induction f; intros * eval_f1 eval_f2;
inversion eval_f1; subst;
inversion eval_f2; subst; try auto.
- replace v with v0 in * by eauto using eval_expr_functional.
eapply IHf; eauto.
- eapply eval_expr_functional; eauto.
Qed.
......@@ -12,21 +12,9 @@ From Coq
From Flover
Require Import Infra.Abbrevs Infra.RationalSimps Infra.RealRationalProps
Infra.RealSimps Infra.Ltacs Commands Environments ErrorAnalysis
ExpressionSemantics IntervalValidation TypeValidator RealRangeValidator
ErrorBounds ErrorValidation AffineForm AffineArithQ AffineArith.
Definition mkErrorPolyQ (err: Q) noise :=
if Qeq_bool err 0 then
Const 0
else
Noise noise err (Const 0).
Definition mkErrorPolyR (err: R) noise :=
if Req_dec_sum err 0%R then
Const 0%R
else
Noise noise err (Const 0%R).
Infra.RealSimps Infra.Ltacs Commands Environments ErrorAnalysis ErrorValidationAAutil
ExpressionSemantics IntervalValidation TypeValidator RealRangeValidator ErrorBounds
ErrorValidation AffineForm AffineArithQ AffineArith.
(** Error bound validator **)
Fixpoint validErrorboundAA (e:expr Q) (* analyzed expression *)
......@@ -248,1550 +236,6 @@ Fixpoint validErrorboundAACmd (f: cmd Q) (* analyzed cmd with let's *)
| Ret e => validErrorboundAA e typeMap A dVars currNoise errMap
end.
Lemma mem_false_find_none V e (expr_map: FloverMap.t (affine_form V)):
FloverMap.mem e expr_map = false <-> FloverMap.find e expr_map = None.
Proof.
split; intros Hmem.
- rewrite FloverMapFacts.P.F.mem_find_b in Hmem.
destruct FloverMap.find; congruence.
- rewrite FloverMapFacts.P.F.mem_find_b.
destruct FloverMap.find; congruence.
Qed.
Lemma afQ2R_mkErrorPolyQ e n:
afQ2R (mkErrorPolyQ e n) = mkErrorPolyR (Q2R e) n.
Proof.
cbn.
unfold mkErrorPolyR, mkErrorPolyQ.
destruct Req_dec_sum.
- destruct Qeq_bool eqn: Heq.
+ cbn.
f_equal; lra.
+ apply Qeq_bool_neq in Heq.
replace 0%R with (Q2R 0) in e0 by lra.
apply eqR_Qeq in e0; lra.
- destruct Qeq_bool eqn: Heq.
+ apply Qeq_bool_iff in Heq.
apply Qeq_eqR in Heq; lra.
+ cbn; f_equal; f_equal.
lra.
Qed.
Lemma mkErrorPolyR_fresh_compat e n1 n2:
(n1 < n2)%nat -> fresh n2 (mkErrorPolyR e n1).
Proof.
intros Hle.
unfold fresh, mkErrorPolyR.
destruct Req_dec_sum; cbn; lia.
Qed.
Lemma toInterval_mkErrorPolyR e n:
(0 <= e)%R ->
toInterval (mkErrorPolyR e n) = (-e, e)%R.
Proof.
intros.
unfold toInterval, mkErrorPolyR; destruct Req_dec_sum; cbn.
- subst.
f_equal; lra.
- rewrite Rabs_pos_eq; auto.
f_equal; lra.
Qed.
Lemma get_const_mkErrorPolyR e n:
get_const (mkErrorPolyR e n) = 0%R.
Proof.
unfold mkErrorPolyR; destruct Req_dec_sum; now cbn.
Qed.
Lemma toInterval_negate_aff a:
toInterval (negate_aff a) = (-(snd (toInterval a)), -(fst (toInterval a)))%R.
Proof.
unfold negate_aff, mult_aff_const, mult_aff.
remember (a, (Const (-1)%R)) as a12.
assert (fst a12 = a /\ snd a12 = (Const (-1)%R)) as Havals by now rewrite Heqa12.
destruct Havals as [Heqa1 Heqa2].
rewrite <- Heqa1 in *.
clear Heqa1 Heqa12 a.
functional induction (mult_aff_aux a12); cbn in *; try congruence.
- destruct Req_dec_sum; [|lra].
unfold toInterval.
cbn.
repeat rewrite Rminus_0_r.
repeat rewrite Rplus_0_r.
inversion Heqa2; subst; clear Heqa2.
f_equal; lra.
- specialize (IHa Heqa2).
destruct (Req_dec_sum (radius a1' * 0) 0); [|lra].
destruct Req_dec_sum; [|lra].
unfold toInterval in *.
cbn in *.
inversion Heqa2; subst; clear Heqa2.
inversion IHa; clear IHa.
field_rewrite ((- (get_const a1' + (Rabs v1 + radius a1'))) = (- (get_const a1' + radius a1')) - Rabs v1)%R.
field_rewrite ((- (get_const a1' - (Rabs v1 + radius a1'))) = (- (get_const a1' - radius a1')) + Rabs v1)%R.
rewrite <- H0.
rewrite <- H1.
field_rewrite (v1 * -1 = -v1)%R.
rewrite Rabs_Ropp.
f_equal; lra.
Qed.
Lemma from_intv_from_interval (l h: Q) n:
afQ2R (fromIntv (l, h) n) = fromInterval (Q2R l, Q2R h) n.
Proof.
unfold fromInterval, fromIntv.
cbn.
assert (Const (Q2R (h / (2 # 1) + l / (2 # 1))) = Const (Q2R h / 2 + Q2R l / 2)%R) as H'.
{
rewrite Q2R_plus; rewrite Q2R_div; try lra.
rewrite Q2R_div; try lra.
now field_rewrite (Q2R (2 # 1) = 2)%R.
}
destruct (Qeq_bool l h) eqn: Hc.
- apply Qeq_bool_iff in Hc.
apply Qeq_eqR in Hc.
rewrite Hc.
cbn.
destruct (Req_dec_sum (Q2R h) (Q2R h)); try contradiction.
now setoid_rewrite <- Hc at 2.
- apply Qeq_bool_neq in Hc.
destruct (Req_dec_sum (Q2R l) (Q2R h)) as [Hc__R|]; try (apply eqR_Qeq in Hc__R; contradiction).
cbn.
f_equal; [|assumption].
rewrite <- Q2R_max.
repeat rewrite Q2R_minus.
repeat rewrite Q2R_plus.
repeat rewrite Q2R_div; try lra.
now field_rewrite (Q2R (2 # 1) = 2)%R.
Qed.
Lemma computeErrorR_pos x m:
(0 <= computeErrorR x m)%R.
Proof.
unfold computeErrorR.
destruct m; try lra; try (apply Rmult_le_pos; [apply Rabs_pos|apply mTypeToR_pos_R]).
apply mTypeToR_pos_R.
Qed.
Lemma RmaxAbsFun_symmetric_pos_arg x:
(0 <= x)%R -> RmaxAbsFun (-x, x)%R = x.
Proof.
intros Hposx.
unfold RmaxAbsFun.
cbn.
rewrite Rmax_right; [apply Rabs_right|rewrite Rabs_Ropp]; lra.
Qed.
Lemma Rle_Ropp_pos x:
(0 <= x)%R -> (-x <= x)%R.
Proof.
intros; lra.
Qed.
Lemma RmaxAbsFun_iv iv x:
iv = (-x, x)%R -> (0 <= x)%R -> (- RmaxAbsFun iv, RmaxAbsFun iv)%R = iv.
Proof.
intros Hivsym Hxpos.
rewrite Hivsym.
unfold RmaxAbsFun.
cbn.
rewrite Rabs_Ropp.
rewrite Rmax_right; [|apply Rle_refl].
rewrite Rabs_pos_eq; auto.
Qed.
Lemma const_0_sym a:
get_const a = 0%R <-> toInterval a = (-(AffineArith.radius a), AffineArith.radius a)%R.
Proof.
split.
- intros Hc.
unfold toInterval.
rewrite Hc.
cbn.
f_equal; lra.
- intros Hiv.
unfold toInterval in Hiv.
cbn in Hiv.
inversion Hiv; subst; clear Hiv.
lra.
Qed.
Lemma const_0_plus a1 a2:
get_const a1 = 0%R ->
get_const a2 = 0%R ->
get_const (plus_aff a1 a2) = 0%R.
Proof.
intros Hc1 Hc2.
unfold plus_aff.
remember (a1, a2) as a12.
assert (fst a12 = a1 /\ snd a12 = a2) as Havals by now rewrite Heqa12.
destruct Havals as [Heqa1 Heqa2].
rewrite <- Heqa1 in Hc1.
rewrite <- Heqa2 in Hc2.
clear Heqa1 Heqa2 Heqa12 a1 a2.
functional induction (plus_aff_tuple a12); cbn in *; try lra; now apply IHa.
Qed.
Lemma plus_aff_to_interval_sym_compat af1 af2 v1 v2:
toInterval af1 = (-v1, v1)%R ->
toInterval af2 = (-v2, v2)%R ->
toInterval (plus_aff af1 af2) = (- (radius (plus_aff af1 af2)), (radius (plus_aff af1 af2)))%R.
Proof.
intros Hiv1 Hiv2.
unfold toInterval in Hiv1, Hiv2.
cbn in Hiv1, Hiv2.
inversion Hiv1; subst; clear Hiv1.
assert (get_const af1 = 0%R) as Hc1 by lra.
inversion Hiv2; subst; clear Hiv2.
assert (get_const af2 = 0%R) as Hc2 by lra.
pose proof (const_0_plus _ _ Hc1 Hc2) as Hc__p.
unfold toInterval.
cbn.
rewrite Hc__p.
f_equal; lra.
Qed.
Lemma const_0_mult a1 a2 n:
get_const a1 = 0%R ->
get_const a2 = 0%R ->
get_const (mult_aff a1 a2 n) = 0%R.
Proof.
intros Hc1 Hc2.
unfold mult_aff.
destruct Req_dec_sum as [Heq|Heq].
Set Default Goal Selector "all".
remember (a1, a2) as a12.
assert (fst a12 = a1 /\ snd a12 = a2) as Havals by now rewrite Heqa12.
destruct Havals as [Heqa1 Heqa2].
rewrite <- Heqa1 in Hc1.
rewrite <- Heqa2 in Hc2.
cbn.
clear Heqa1 Heqa2 Heqa12 Heq a1 a2.
functional induction (mult_aff_aux a12); cbn in *; try lra; subst; lra.
Set Default Goal Selector "1".
Qed.
Lemma const_0_mult_l a1 a2 n:
get_const a1 = 0%R ->
get_const (mult_aff a1 a2 n) = 0%R.
Proof.
intros Hc1.
unfold mult_aff.
destruct Req_dec_sum as [Heq|Heq].
Set Default Goal Selector "all".
remember (a1, a2) as a12.
assert (fst a12 = a1 /\ snd a12 = a2) as Havals by now rewrite Heqa12.
destruct Havals as [Heqa1 Heqa2].
rewrite <- Heqa1 in Hc1.
cbn.
clear Heqa1 Heqa2 Heqa12 Heq a1 a2.
functional induction (mult_aff_aux a12); cbn in *; try lra; subst; lra.
Set Default Goal Selector "1".
Qed.
Lemma const_0_mult_r a1 a2 n:
get_const a2 = 0%R ->
get_const (mult_aff a1 a2 n) = 0%R.
Proof.
intros Hc2.
unfold mult_aff.
destruct Req_dec_sum as [Heq|Heq].
Set Default Goal Selector "all".
remember (a1, a2) as a12.
assert (fst a12 = a1 /\ snd a12 = a2) as Havals by now rewrite Heqa12.
destruct Havals as [Heqa1 Heqa2].
rewrite <- Heqa2 in Hc2.
cbn.
clear Heqa1 Heqa2 Heqa12 Heq a1 a2.
functional induction (mult_aff_aux a12); cbn in *; try lra; subst; lra.
Set Default Goal Selector "1".
Qed.
Lemma mult_aff_to_interval_sym_compat af1 af2 v1 v2 n:
toInterval af1 = (-v1, v1)%R ->
toInterval af2 = (-v2, v2)%R ->
toInterval (mult_aff af1 af2 n) =
(- (radius (mult_aff af1 af2 n)), (radius (mult_aff af1 af2 n)))%R.
Proof.
intros Hiv1 Hiv2.
unfold toInterval in Hiv1, Hiv2.
cbn in Hiv1, Hiv2.
inversion Hiv1; subst; clear Hiv1.
assert (get_const af1 = 0%R) as Hc1 by lra.
inversion Hiv2; subst; clear Hiv2.
assert (get_const af2 = 0%R) as Hc2 by lra.
pose proof (const_0_mult _ _ n Hc1 Hc2) as Hc__p.
unfold toInterval.
cbn.
rewrite Hc__p.
f_equal; lra.
Qed.
Lemma mult_aff_to_interval_sym_compat_l af1 af2 v1 n:
toInterval af1 = (-v1, v1)%R ->
toInterval (mult_aff af1 af2 n) =
(- (radius (mult_aff af1 af2 n)), (radius (mult_aff af1 af2 n)))%R.
Proof.
intros Hiv1.
unfold toInterval in Hiv1.
cbn in Hiv1.
inversion Hiv1; subst; clear Hiv1.
assert (get_const af1 = 0%R) as Hc1 by lra.
pose proof (const_0_mult_l _ af2 n Hc1) as Hc__p.
unfold toInterval.
cbn.
rewrite Hc__p.
f_equal; lra.
Qed.
Lemma mult_aff_to_interval_sym_compat_r af1 af2 v2 n:
toInterval af2 = (-v2, v2)%R ->
toInterval (mult_aff af1 af2 n) =
(- (radius (mult_aff af1 af2 n)), (radius (mult_aff af1 af2 n)))%R.
Proof.
intros Hiv2.
unfold toInterval in Hiv2.
cbn in Hiv2.
inversion Hiv2; subst; clear Hiv2.
assert (get_const af2 = 0%R) as Hc2 by lra.
pose proof (const_0_mult_r af1 _ n Hc2) as Hc__p.
unfold toInterval.
cbn.
rewrite Hc__p.
f_equal; lra.
Qed.
Lemma negate_aff_to_interval_sym_compat a v:
toInterval a = (-v, v)%R ->
toInterval (negate_aff a) = toInterval a.
Proof.
intros Hiv.
rewrite toInterval_negate_aff.
rewrite Hiv.
cbn; f_equal; lra.
Qed.
Lemma subtract_aff_to_interval_sym_compat af1 af2 v1 v2:
toInterval af1 = (-v1, v1)%R ->
toInterval af2 = (-v2, v2)%R ->
toInterval (subtract_aff af1 af2) =
(- (radius (subtract_aff af1 af2)), (radius (subtract_aff af1 af2)))%R.
Proof.
intros Hiv1 Hiv2.
unfold subtract_aff.
eapply plus_aff_to_interval_sym_compat with (v1 := v1); eauto.
rewrite <- Hiv2.
erewrite negate_aff_to_interval_sym_compat; eauto.
Qed.
Lemma plus_aff_0_r a:
plus_aff a (Const 0%R) = a.
Proof.
unfold plus_aff.
remember (a, (Const 0%R)) as a12.
assert (fst a12 = a /\ snd a12 = (Const 0%R)) as Havals by now rewrite Heqa12.
destruct Havals as [Heqa1 Heqa2].
rewrite <- Heqa1.
clear Heqa1 Heqa12 a.
functional induction (plus_aff_tuple a12); cbn in *; try congruence.
- f_equal.
inversion Heqa2; lra.
- inversion Heqa2; subst; clear Heqa2.
specialize (IHa ltac:(reflexivity)).
now rewrite IHa.
Qed.
Lemma radius_plus_from_interval a x n:
fresh n a ->
(0 <= x)%R ->
radius (plus_aff a (fromInterval (-x, x) n))%R = ((radius a) + x)%R.
Proof.
intros Hfresh Hxpos.
induction a.
- unfold fromInterval; cbn.
destruct Req_dec_sum; cbn.
+ lra.
+ field_rewrite (x / 2 + - x / 2 = 0)%R.
rewrite Rmax_right; try lra.
rewrite Rabs_pos_eq; lra.
- assert (n0 < n)%nat as Hlt.
{
unfold fresh in Hfresh.
cbn in Hfresh.
eapply Nat.le_lt_trans; try exact Hfresh.
apply get_mia_monotonic.
}
apply fresh_noise_compat in Hfresh.
specialize (IHa Hfresh).
unfold plus_aff.
unfold fromInterval in *; cbn in *.
destruct Req_dec_sum; field_rewrite (Rabs v + radius a + x = radius a + x + Rabs v)%R.
+ rewrite <- IHa.
replace x with 0%R by lra.
unfold plus_aff; rewrite plus_aff_tuple_equation; cbn.
lra.
+ field_rewrite (x / 2 + - x / 2 = 0)%R.
rewrite Rmax_right; try lra.
unfold plus_aff.
rewrite plus_aff_tuple_equation.
assert (n0 <> n) as Hneq by lia.
rewrite <- Nat.eqb_neq in Hneq.
rewrite Hneq.
rewrite <- Nat.ltb_lt in Hlt.
rewrite Hlt.
cbn.
rewrite plus_aff_tuple_equation.
cbn.
rewrite Rabs_pos_eq; try lra.
rewrite Rminus_0_r.
field_rewrite (x + (Rabs v + radius (plus_aff_tuple (a, Const 0))) =
x + radius (plus_aff_tuple (a, Const 0)) + Rabs v)%R.
f_equal.
replace (plus_aff_tuple (a, Const 0%R)) with (plus_aff a (Const 0%R)) by trivial.
rewrite plus_aff_0_r.
lra.
Qed.
Lemma af_evals_from_interval_updMap iv noise map vR:
((fst iv) <= vR <= (snd iv))%R ->
exists q : noise_type,
af_evals (fromInterval iv noise) vR (updMap map noise q).
Proof.
intros interval_containment.
destruct (Req_dec (IVlo iv) (IVhi iv)) as [Heq|Heq].
{
exists noise_zero.
unfold af_evals, fromInterval.
rewrite Heq.
cbn.
destruct Req_dec_sum; [|lra].
cbn in Heq |-*.
lra.
}
unfold af_evals, fromInterval.
destruct Req_dec_sum; [lra|].
cbn in Heq |-*.
setoid_rewrite upd_sound.
simpl.
apply Rmax_case_strong.
- intros Hmax.
pose (l := fst iv).
pose (h := snd iv).
fold l h in Hmax, interval_containment, Heq |-*.
pose (noise_expression := ((vR - h / 2 - l / 2) / (h / 2 + l / 2 - l))%R).
assert (-(1) <= noise_expression <= 1)%R as Hnoise.
{
unfold noise_expression.
apply Rabs_Rle_condition.
destruct (Rle_lt_dec (h / 2 + l / 2 - l) 0)%R as [Hle0 | Hle0].
- apply Rle_lt_or_eq_dec in Hle0; destruct Hle0 as [Hlt | Hlt];
try (field_simplify in Hlt; assert (h = l) as Hz by lra; lra).
- rewrite Rdiv_abs_le_bounds; try lra.
assert (0 < h - l)%R as H1 by lra.
field_rewrite (vR - h / 2 - l /2 = vR - (h + l) / 2)%R.
field_rewrite (1 * (h / 2 + l / 2 - l) = (h - l) / 2)%R.
apply Rabs_Rle_condition; lra.
}
rename noise into inoise.
pose (noise := exist (fun x => -(1) <= x <= 1)%R noise_expression Hnoise).
exists noise.
unfold noise, noise_expression.
simpl.
field.
intros Hnotz.
field_simplify in Hnotz.
assert (h = l) as Hz by lra.
lra.
- intros Hmax.
pose (l := fst iv).
pose (h := snd iv).
fold l h in Hmax, interval_containment, Heq |-*.
pose (noise_expression := ((vR - h / 2 - l / 2) / (h / 2 + l / 2 - l))%R).
assert (-(1) <= noise_expression <= 1)%R as Hnoise.
{
unfold noise_expression.
apply Rabs_Rle_condition.
destruct (Rle_lt_dec (h / 2 + l / 2 - l) 0)%R as [Hle0 | Hle0].
- apply Rle_lt_or_eq_dec in Hle0; destruct Hle0 as [Hlt | Hlt];
try (field_simplify in Hlt; assert (h = l) as Hz by lra; lra).
- rewrite Rdiv_abs_le_bounds; try lra.
assert (0 < h - l)%R as H1 by lra.
field_rewrite (vR - h / 2 - l /2 = vR - (h + l) / 2)%R.
field_rewrite (1 * (h / 2 + l / 2 - l) = (h - l) / 2)%R.
apply Rabs_Rle_condition; lra.
}
rename noise into inoise.
pose (noise := exist (fun x => -(1) <= x <= 1)%R noise_expression Hnoise).
exists noise.
unfold noise, noise_expression.
simpl.
field.
intros Hnotz.
field_simplify in Hnotz.
assert (h = l) as Hz by lra.
lra.
Qed.
Lemma af_evals_mkErrorPolyR_updMap e noise map vR:
(0 <= e)%R ->
(Rabs vR <= e)%R ->
exists q : noise_type,
af_evals (mkErrorPolyR e noise) vR (updMap map noise q).
Proof.
intros Hepos Hbounds.
replace (mkErrorPolyR e noise) with (fromInterval (-e, e)%R noise).
- apply af_evals_from_interval_updMap; cbn; now rewrite <- Rabs_Rle_condition.
- unfold mkErrorPolyR, fromInterval; cbn.
destruct Req_dec_sum.
+ destruct Req_dec_sum; f_equal; lra.
+ destruct Req_dec_sum; try lra.
f_equal; f_equal; try lra.
rewrite Rmax_right; lra.
Qed.
Lemma af_evals_updMap_compat a map n q v:
fresh n a ->
af_evals a v map <-> af_evals a v (updMap map n q).
Proof.
intros Hfresh.
unfold af_evals.
erewrite eval_updMap_compat with (n := n) (q := q); eauto.
reflexivity.
Qed.
Lemma RmaxAbsFun_pos iv:
(0 <= RmaxAbsFun iv)%R.
Proof.
unfold RmaxAbsFun.
apply Rmax_case_strong; intros; apply Rabs_pos.
Qed.
Lemma Q2R_Q2RP_fst iv:
Q2R (fst iv) = fst (Q2RP iv).
Proof.
now destruct iv.
Qed.
Lemma Q2R_Q2RP_snd iv:
Q2R (snd iv) = snd (Q2RP iv).
Proof.
now destruct iv.
Qed.
Lemma Q2RP_addIntv iv1 iv2:
Q2RP (addIntv iv1 iv2) = addInterval (Q2RP iv1) (Q2RP iv2).
Proof.
cbn; unfold addInterval, absIntvUpd.
rewrite Q2R_min4, Q2R_max4.
repeat rewrite Q2R_plus.
now destruct iv1, iv2; cbn.
Qed.
Lemma Q2RP_subtractIntv iv1 iv2:
Q2RP (subtractIntv iv1 iv2) = subtractInterval (Q2RP iv1) (Q2RP iv2).
Proof.
cbn; unfold subtractInterval, absIntvUpd.
rewrite Q2R_min4, Q2R_max4.
repeat rewrite Q2R_plus.
repeat rewrite Q2R_opp.
now destruct iv1, iv2; cbn.
Qed.
Lemma Q2RP_multIntv iv1 iv2:
Q2RP (multIntv iv1 iv2) = multInterval (Q2RP iv1) (Q2RP iv2).
Proof.
cbn; unfold multInterval, absIntvUpd.
rewrite Q2R_min4, Q2R_max4.
repeat rewrite Q2R_mult.
now destruct iv1, iv2; cbn.
Qed.
Lemma Q2RP_invertIntv iv:
~ fst iv == 0 ->
~ snd iv == 0 ->
Q2RP (invertIntv iv) = invertInterval (Q2RP iv).
Proof.
intros.
cbn; unfold invertInterval, mkInterval.
repeat rewrite Q2R_inv; auto.
now destruct iv; cbn.
Qed.
Lemma Q2RP_divideIntv iv1 iv2:
~ fst iv2 == 0 ->
~ snd iv2 == 0 ->
Q2RP (divideIntv iv1 iv2) = divideInterval (Q2RP iv1) (Q2RP iv2).
Proof.
intros.
cbn;