|
| 1 | +""" |
| 2 | +Farey Sequence Generator |
| 3 | +
|
| 4 | +The Farey sequence of order n is the sequence of completely reduced |
| 5 | +fractions between 0 and 1 which have denominators less than or equal to n, |
| 6 | +arranged in increasing order. |
| 7 | +
|
| 8 | +Reference: https://en.wikipedia.org/wiki/Farey_sequence |
| 9 | +""" |
| 10 | + |
| 11 | +from fractions import Fraction |
| 12 | + |
| 13 | + |
| 14 | +def farey_sequence(order: int) -> list[Fraction]: |
| 15 | + """ |
| 16 | + Generate the Farey sequence of a given order in ascending order. |
| 17 | +
|
| 18 | + :param order: The maximum denominator allowed in the fractions. |
| 19 | + :return: A list of Fraction objects in ascending order. |
| 20 | +
|
| 21 | + >>> farey_sequence(1) |
| 22 | + [Fraction(0, 1), Fraction(1, 1)] |
| 23 | + >>> farey_sequence(2) |
| 24 | + [Fraction(0, 1), Fraction(1, 2), Fraction(1, 1)] |
| 25 | + >>> farey_sequence(5) |
| 26 | + [Fraction(0, 1), Fraction(1, 5), Fraction(1, 4), Fraction(1, 3), Fraction(2, 5), Fraction(1, 2), Fraction(3, 5), Fraction(2, 3), Fraction(3, 4), Fraction(4, 5), Fraction(1, 1)] |
| 27 | + >>> farey_sequence(0) |
| 28 | + Traceback (most recent call last): |
| 29 | + ... |
| 30 | + ValueError: Order must be a positive integer |
| 31 | + >>> farey_sequence(-3) |
| 32 | + Traceback (most recent call last): |
| 33 | + ... |
| 34 | + ValueError: Order must be a positive integer |
| 35 | + >>> farey_sequence("5") |
| 36 | + Traceback (most recent call last): |
| 37 | + ... |
| 38 | + TypeError: Order must be an integer |
| 39 | + """ |
| 40 | + if not isinstance(order, int) or isinstance(order, bool): |
| 41 | + raise TypeError("Order must be an integer") |
| 42 | + if order < 1: |
| 43 | + raise ValueError("Order must be a positive integer") |
| 44 | + |
| 45 | + sequence: list[Fraction] = [Fraction(0, 1)] |
| 46 | + numerator1, denominator1 = 0, 1 |
| 47 | + numerator2, denominator2 = 1, order |
| 48 | + |
| 49 | + sequence.append(Fraction(numerator2, denominator2)) |
| 50 | + |
| 51 | + while numerator2 != 1 or denominator2 != 1: |
| 52 | + scale_factor = (denominator1 + order) // denominator2 |
| 53 | + next_numerator = scale_factor * numerator2 - numerator1 |
| 54 | + next_denominator = scale_factor * denominator2 - denominator1 |
| 55 | + |
| 56 | + sequence.append(Fraction(next_numerator, next_denominator)) |
| 57 | + |
| 58 | + numerator1, denominator1 = numerator2, denominator2 |
| 59 | + numerator2, denominator2 = next_numerator, next_denominator |
| 60 | + |
| 61 | + return sequence |
| 62 | + |
| 63 | + |
| 64 | +if __name__ == "__main__": |
| 65 | + import doctest |
| 66 | + |
| 67 | + doctest.testmod() |
| 68 | + |
| 69 | + print("Farey sequence of order 4:") |
| 70 | + print(farey_sequence(4)) |
| 71 | + |
0 commit comments