Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Farey.ml
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
(*** *** Farey sequences (reduced fractions between 0 and 1 with bounded denominator) *** *** https://en.wikipedia.org/wiki/Farey_sequence ***) (* the Farey sequence of order dmax is the ordered sequence of irreducible * fractions between 0 and 1, included, whose denominator is at most dmax. * fractions are pairs (a,b) of coprime integers with 0 ⩽ a < b. *) type t = int * int (* the Farey sequence is symmetric (if the fraction (a, b) is irreducible, then * (b−a, b) too), so we can easily change the direction. *) let sym (a, b) = (b-a, b) (* THEOREM 1: * the fractions (a, b) and (c, d) are adjacent in the Farey sequence of order * dmax if and only if: * (1) b, d ⩽ dmax < b+d * (2) b×c − a×d = 1 * at order b+d, the fractions (a, b), (a+c, b+d), (c, d) are adjacent. * the middle fraction is called the mediant (in this case, it is guaranteed to * be in irreducible form). * so the terms of the Farey sequence of some order, between two given fractions * which are adjacent at some lower order, are obtained by inserting mediants * (this is how the Stern-Brocot tree is constructed). * * theorem 1 allows us to compute in O(1) the successor at order dmax of some * fraction (a, b), provided we know the successor (c0, d0) at some lower order. *) let assert_adjacent_fractions dmax (a, b) (c, d) = assert ((a,b) = (0,1) || 0 < a && a < b && b <= dmax (*&& gcd a b = 1*)) ; assert ((c,d) = (1,1) || 0 < c && c < d && d <= dmax (*&& gcd c d = 1*)) ; assert (b*c - a*d = 1) ; (* implies gcd a b = 1 && gcd c d = 1 *) assert (dmax < b + d) (* THEOREM 2: * for any three fractions (a, b), (c, d), (e, f) which are adjacent at order * dmax, (c, d) is equal to the mediant (a+e, b+f) of (a, b) and (e, f) * (however, that mediant is not always in irreducible form). * * theorem 2 allows us to compute in O(1) the successor at order dmax of two * adjacent fractions (a, b), (c, d); hence, we can iterate in O(n) = O(dmax²) * on the Farey sequence of order dmax, where n is the length of the sequence * (the length of the sequence is the sum of the totient function φ, is is * asymptotically equivalent to 3∕π² dmax²). *) (* [iter_farey dmax f] iterates [f] on every fraction of the Farey sequence of * order [dmax]. the optional arguments [starting1] and [starting2] are two * adjacent fractions in the sequence, which are taken as the starting point * (instead of (0,1) and (1,dmax)). *) let rec iter_farey dmax ?starting1 ?starting2 f = assert (dmax > 0) ; let rec loop (a, b) (c, d) = assert_adjacent_fractions dmax (a, b) (c, d) ; f (c, d) ; if d <> 1 then begin let k = (dmax + b) / d in loop (c, d) (k*c-a, k*d-b) end in let frac1, frac2 = begin match starting1, starting2 with | None, None -> (0, 1), (1, dmax) | Some frac1, None -> frac1, next_farey dmax frac1 | None, Some frac2 -> prev_farey dmax frac2, frac2 | Some frac1, Some frac2 -> assert_adjacent_fractions dmax frac1 frac2 ; frac1, frac2 end in f frac1 ; loop frac1 frac2 (* [next_farey dmax frac] returns the successor fraction of [frac] in the Farey * sequence of order [dmax]. *) and next_farey dmax (a, b) = assert ((a, b) <> (1,1)) ; (* compute naively the successor (c₀, d₀) of (a, b) at order b. * * TODO: constant-factor optimization: start from beginning or end of * sequence, whichever is nearest, and use symetry * * TODO: I think we can find a successor much more efficiently, using the * extended Euclidean algorithm: since (a,b) are coprime, we can find (c,d) * such that bc − ad = 1 and and 0 < c ≤ a and 0 ≤ d < b. Furthermore, * a < b implies c < d. So (a,b) and (c,d) are adjacent fractions at order b? * To be checked… *) let (c0, d0) = let exception Found of (int * int) in let found = ref false in begin match iter_farey b begin fun frac' -> if !found then raise (Found frac') else found := (frac' = (a, b)) end with | exception Found frac' -> frac' | () -> assert false end in (* deduce the successor (c, d) of (a, b) at order dmax. * explanation: if (a, b) and (c₀, d₀) are adjacent at order b, * then (a, b) and (a + c₀, b + d₀) are adjacent at order b + d₀, * thus (a, b) and (2×a + c₀, 2×b + d₀) are adjacent at order 2×b + d₀, * and so on, * so that (a, b) and (k×a + c₀, k×b + d₀) are adjacent at order k×b + d₀, * and we take the greatest k such that the denominator is less than dmax. *) let k = (dmax - d0) / b in let c = k*a + c0 in let d = k*b + d0 in assert_adjacent_fractions dmax (a, b) (c, d) ; (c, d) and prev_farey dmax frac = sym @@ next_farey dmax @@ sym frac let rev_iter_farey dmax ?starting1 ?starting2 f = let starting1 = begin match starting1 with | Some frac1 -> Some (sym frac1) | None -> None end and starting2 = begin match starting2 with | Some frac2 -> Some (sym frac2) | None -> None end in iter_farey dmax ?starting1 ?starting2 (fun frac -> f @@ sym frac) (* [list_farey dmax] returns the Farey sequence of order [dmax] as a list. *) let list_farey dmax = let li = ref [] in iter_farey dmax (fun frac -> li := frac :: !li) ; List.rev !li (* TODO: generate sequences of type [Seq.t] rather than [list]. *) (* Tests. *) (* FIXME: Use an actual tool for unit tests. *) let () = assert (next_farey 8 (1, 3) = (3, 8)) ; assert (prev_farey 8 (3, 7) = (2, 5)) ; assert ( list_farey 8 = [(0, 1); (1, 8); (1, 7); (1, 6); (1, 5); (1, 4); (2, 7); (1, 3); (3, 8); (2, 5); (3, 7); (1, 2); (4, 7); (3, 5); (5, 8); (2, 3); (5, 7); (3, 4); (4, 5); (5, 6); (6, 7); (7, 8); (1, 1)] )