aboutsummaryrefslogtreecommitdiff
path: root/src/Util/Factorize.v
blob: 12893cd7580e48b0b62079c88fe360ebe19f3c69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
Require Import Coq.Bool.Sumbool.
Require Import Coq.micromega.Psatz.
Require Import Coq.NArith.NArith.
Require Import Coq.PArith.PArith.
Require Import Coq.Lists.List.
Require Import Coq.Init.Wf.

Local Open Scope positive_scope.

(* given [n] and [d₀], returns, possibly, [d, v] where [d ≥ d₀] is small and [d * v = n]

   Precondition: [d₀] is either 2, or an odd number > 2 *)
Definition find_N_factor (factor_val : N) (d0 : N) : option (N * N).
Proof.
  refine (let (d', r) := N.div_eucl factor_val d0 in (* special-case the first one, which might be 2 *)
          if N.eqb 0 r
          then Some (d0, d')
          else
            let sfactor_val := N.sqrt factor_val in
            Fix
              (Acc_intro_generator (S (S (S (N.to_nat (N.div2 sfactor_val))))) (@N.gt_wf sfactor_val)) (fun _ => option (N * N)%type)
              (fun d find_N_factor
               => let (d', r) := N.div_eucl factor_val d in
                  if N.eqb 0 r
                  then Some (d, d')
                  else let d' := (d + 2)%N in
                       if Sumbool.sumbool_of_bool (N.leb d' sfactor_val)
                       then find_N_factor d' _
                       else None)
              (if N.eqb 2%N d0 then 3%N else (d0 + 2)%N)).
  { subst sfactor_val d'.
    clear find_N_factor.
    let H := match goal with H : _ = true |- _ => H end in
    clear -H;
      abstract (
          apply N.leb_le in H;
          split; try assumption;
          lia
        ). }
Defined.

(* given [n] and [d₀], gives a list of factors of [n] which are ≥ d₀, lowest to highest *)
Definition factorize' (n : N) : N -> list N.
Proof.
  refine (Fix
            (Acc_intro_generator (S (S (S (S (N.to_nat (N.div2 (N.sqrt n))))))) N.lt_wf_0) (fun _ => N -> list N)
            (fun n factorize cur_max_factor
             => _)
            n).
  refine match find_N_factor n cur_max_factor with
         | Some (d, n') => if Sumbool.sumbool_of_bool (n' <? n)%N
                           then d :: factorize n' _ d
                           else d :: n' :: nil
         | None => n::nil
         end.
  { let H := match goal with H : _ = true |- _ => H end in
    clear -H;
      abstract (
          apply N.ltb_lt in H;
          assumption
        ). }
Defined.

Definition factorize (n : N) : list N := factorize' n 2%N.

Definition factorize_or_fail (n:N) : option (list N) :=
  let factors := factorize n in
  if N.eqb (List.fold_right N.mul 1%N factors) n then Some factors else None.
Lemma product_factorize_or_fail (n:N) (factors:list N)
      (H:Logic.eq (factorize_or_fail n) (Some factors))
  : Logic.eq (List.fold_right N.mul 1%N factors) n.
Proof.  cbv [factorize_or_fail] in H; destruct ((fold_right N.mul 1 (factorize n) =? n)%N) eqn:?;
          try apply N.eqb_eq; congruence. Qed.