The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Math::PlanePath::GcdRationals -- rationals by triangular GCD

SYNOPSIS

 use Math::PlanePath::GcdRationals;
 my $path = Math::PlanePath::GcdRationals->new;
 my ($x, $y) = $path->n_to_xy (123);

DESCRIPTION

This path enumerates X/Y rationals using a method by Lance Fortnow taking a greatest common divisor out of a triangular position. It has the attraction of being both efficient to calculate (a GCD) and completing X/Y blocks with a much smaller N range than the tree based rationals.

    http://blog.computationalcomplexity.org/2004/03/counting-rationals-quickly.html

    13  |      79  80  81  82  83  84  85  86  87  88  89  90
    12  |      67              71      73              77     278
    11  |      56  57  58  59  60  61  62  63  64  65     233 235
    10  |      46      48              52      54     192     196
     9  |      37  38      40  41      43  44     155 157     161
     8  |      29      31      33      35     122     126     130
     7  |      22  23  24  25  26  27      93  95  97  99 101 103
     6  |      16              20      68              76     156
     5  |      11  12  13  14      47  49  51  53     108 111 114
     4  |       7       9      30      34      69      75     124
     3  |       4   5      17  19      39  42      70  74     110
     2  |       2       8      18      32      50      72      98
     1  |       1   3   6  10  15  21  28  36  45  55  66  78  91
    Y=0 |
         --------------------------------------------------------
          X=0   1   2   3   4   5   6   7   8   9  10  11  12  13

The mapping from N to rational is

    N = i + j*(j-1)/2     upper triangle 1 <= i <= j
    gcd = GCD(i,j)
    rational = i/j + gcd-1

which means

    X = (i + j*(gcd-1)) / gcd
    Y = j/gcd

The i,j position is a numbering of points above the X=Y diagonal by rows, in the style of PyramidRows step=1.

    j=4  7  8  9  10
    j=3  4  5  6
    j=2  2  3
    j=1  1
       i=1  2  3  4

If GCD(i,j)=1 then X/Y is simply X=i,Y=j unchanged. This means fractions X/Y < 1 are numbered by rows with increasing numerator, but skipping positions where i,j have a common factor.

The skipped positions where i,j have a common factor become rationals X/Y>1, ie. below the X=Y diagonal. GCD(i,j)-1 is the integer part as R = i/j+(gcd-1). For example N=51 is at i=6,j=10 by rows and that i,j has common factor gcd(6,10)=2 so becomes rational R = 6/10+(2-1) = 3/5+1 = 8/5, ie. X=8,Y=5.

Triangular Numbers

The bottom row Y=1 is the triangular numbers N=1,3,6,10,etc, k*(k-1)/2. Such an N is at i=k,j=k and thus gcd(i,j)=k which divides out to Y=1.

    Y = j/gcd
      = 1       on the bottom row

    X = (i + j*(gcd-1)) / gcd
      = (k + k*(k-1)) / k
      = k-1     successive points on that bottom row

N=1,2,4,7,11,etc in the vertical at X=1 immediately following those triangulars on the bottom row, ie.

    N on X=1 column = Y*(Y-1)/2 + 1

Primes

If N is prime then it's above the sloping line X=2*Y. If N is composite then it might be above or below, but the primes are always above. Here's the table with dots "..." for the X=2*Y line.

           primes and composites above

     6  |      16              20      68
        |                                             .... X=2*Y
     5  |      11  12  13  14      47  49  51  53 ....
        |                                     ....
     4  |       7       9      30      34 .... 69
        |                             ....
     3  |       4   5      17  19 .... 39  42      70   always
        |                     ....                      composite
     2  |       2       8 .... 18      32      50       below
        |             ....
     1  |       1 ..3.  6  10  15  21  28  36  45  55
        |     ....
    Y=0 | ....
         ---------------------------------------------
          X=0   1   2   3   4   5   6   7   8   9  10

Values below X=2*Y such as 39 and 42 are always composite. Values above such as 19 and 30 are either prime or composite. Only X=2,Y=1 is exactly on the line, which is prime N=3 as it happens. Other X=2*k,Y=k are not an X/Y rational in least terms because it has common factor k.

This pattern of primes and composites occurs because N is a multiple of gcd(i,j) when gcd odd, or a multiple of gcd/2 when gcd even.

    N = i + j*(j-1)/2
    gcd = gcd(i,j)

    N = gcd   * (i/gcd + j/gcd * (j-1)/2)  when gcd odd
        gcd/2 * (2i/gcd + j/gcd * (j-1))   when gcd even

If gcd odd then either j/gcd or j-1 is even, taking the "/2". If gcd even then only gcd/2 can come out as a factor since the full gcd might leave both j/gcd and j-1 odd and so the "/2" not an integer. That happens for example to N=70

    N = 70
    i = 4, j = 12     for 4 + 12*11/2 = 70 = N
    gcd(i,j) = 4
    but N is not a multiple of 4, only of 4/2=2

Of course knowing gcd or gcd/2 is a factor is only useful when that factor is 2 or more, so only

    odd gcd with gcd >= 2       means gcd >= 3
    even gcd with gcd/2 >= 2    means gcd >= 4

    so N composite when gcd(i,j) >= 3

If gcd<3 then the "factor" coming out is only 1 and says nothing about whether N is prime or composite. There are both prime and composite N for gcd<3, as can be seen among the values above the X=2*Y line in the table above.

Rows Reverse

Option pairs_order => "rows_reverse" reverses the order of points within the rows of i,j pairs,

    j=4  10  9  8  7
    j=3   6  5  4
    j=2   3  2
    j=1   1
        i=1  2  3  4

The point numbering becomes

    pairs_order => "rows_reverse"

    11  |      66  65  64  63  62  61  60  59  58  57
    10  |      55      53              49      47     209
     9  |      45  44      42  41      39  38     170 168
     8  |      36      34      32      30     135     131
     7  |      28  27  26  25  24  23     104 102 100  98
     6  |      21              17      77              69
     5  |      15  14  13  12      54  52  50  48     118
     4  |      10       8      35      31      76      70
     3  |       6   5      20  18      43  40      75  71
     2  |       3       9      19      33      51      73
     1  |       1   2   4   7  11  16  22  29  37  46  56
    Y=0 |
         ------------------------------------------------
          X=0   1   2   3   4   5   6   7   8   9  10  11

The triangular numbers per "Triangular Numbers" above are now in the X=1 column, ie. at the left rather than the bottom. The Y=1 bottom row is the next after each triangular, ie. T(X)+1.

Diagonals

Option pairs_order => "diagonals_down" takes the i,j pairs by diagonals down from the Y axis. pairs_order => "diagonals_up" likewise but upwards from the X=Y centre up to the Y axis. This is in the style of the DiagonalsOctant path.

    diagonals_down                    diagonals_up

    j=7  13                           j=7  16
    j=6  10 14                        j=6  12 15
    j=5   7 11 15                     j=5   9 11 14
    j=4   5  8 12 16                  j=4   6  8 10 13
    j=3   3  6  9                     j=3   4  5  7
    j=2   2  4                        j=2   2  3
    j=1   1                           j=1   1
        i=1  2  3  4                      i=1  2  3  4

The resulting path becomes

    pairs_order => "diagonals_down"

     9  |     21 27    40 47    63 72
     8  |     17    28    41    56    74
     7  |     13 18 23 29 35 42    58 76
     6  |     10          30    44
     5  |      7 11 15 20    32 46 62 80
     4  |      5    12    22    48    52
     3  |      3  6    14 24    33 55
     2  |      2     8    19    34    54
     1  |      1  4  9 16 25 36 49 64 81
    Y=0 |
         --------------------------------
          X=0  1  2  3  4  5  6  7  8  9

    pairs_order => "diagonals_up"

     9  |     25 29    39 45    58 65
     8  |     20    28    38    50    80
     7  |     16 19 23 27 32 37    63 78
     6  |     12          26    48
     5  |      9 11 14 17    35 46 59 74
     4  |      6    10    24    44    54
     3  |      4  5    15 22    34 51
     2  |      2     8    18    33    52
     1  |      1  3  7 13 21 31 43 57 73
    Y=0 |
         --------------------------------
          X=0  1  2  3  4  5  6  7  8  9

For "diagonals_down" the Y=1 bottom row is the perfect squares which are at i=j in the DiagonalsOctant and have gcd(i,j)=i thus becoming X=i,Y=1.

The gcd shears moves points downwards and shears them across horizontally.

      | 1
      |   1     gcd=1 slope=-1
      |     1
      |       1
      |         1
      |           1
      |             1
      |               1
      |                 1
      |                 .    gcd=2 slope=0
      |               .   2
      |             .     2     3  gcd=3 slope=1
      |           .       2   3           gcd=4 slope=2
      |         .         2 3         4
      |       .           3       4       5     gcd=5 slope=3
      |     .                 4      5
      |   .               4     5
      | .                 5
      +-------------------------------

The line of "1"s is the diagonal with gcd=1 and thus X,Y=i,j unchanged.

The line of "2"s is when gcd=2 so X=(i+j)/2,Y=j/2. Since i+j=d is constant within the diagonal this makes X=d fixed, ie. a vertical.

Then gcd=3 becomes X=(i+2j)/3 which slopes across by +1 for each i, or gcd=4 X=(i+3j)/4 slope +2, etc.

Of course only some of the points in a diagonal have a given gcd, but those which do are transformed this way. The effect is that for N up to a given diagonal row all the "*" points in the following are traversed, plus extras in wedge shaped arms out to the side.

     | *
     | * *                 up to a given diagonal points "*"
     | * * *               all visited, plus some wedges out
     | * * * *             to the right
     | * * * * *
     | * * * * *   /
     | * * * * * /  --
     | * * * * *  --
     | * * * * *--
     +--------------

In terms of the rationals X/Y the effect is that up to N=d^2 diagonal d=2j the fractions enumerated are

    N=d^2
    enumerates to num <= d and num+den <= 2*d

FUNCTIONS

See "FUNCTIONS" in Math::PlanePath for behaviour common to all path classes.

$path = Math::PlanePath::GcdRationals->new ()
$path = Math::PlanePath::GcdRationals->new (pairs_order => $str)

Create and return a new path object. The pairs_order option can be

    "rows"               (default)
    "rows_reverse"
    "diagonals_down"
    "diagonals_up"

FORMULAS

X,Y to N

The defining formula above for X,Y can be reversed

    X/Y = i/j + g-1
    g-1 = floor(X/Y)

    Y = j/g
    X = ((g-1)*j + i)/g

so

    j = Y*g
    i = X*g - (g-1)*Y*g

So N = i + j*(j-1)/2 = X*g - (g-1)*Y*g + Y*g*(Y*g-1)/2 = X*g + ((Y-2)*g + 1)*Y*g/2 = (((Y-2)*g + 1)*Y + 2X)*g/2

The /2 division is exact. If Y and g are both odd and so don't take that divisor then the term (Y-2)*g+1 is odd*odd+1 so even.

Y*g in the formulas is the first multiple of Y which is strictly greater than X. It can be formed from the g-1=floor(X/Y) division,

    X = Y*quot + rem     division
    g = quot+1
    Y*g = Y*(q+1) = X+Y-rem
        = X+Y-rem

If a division gives quotient and remainder for the same price then X+Y-rem instead of Y*g might reduce a multiply to instead an add or subtract.

OEIS

This enumeration of rationals is in Sloane's Online Encyclopedia of Integer Sequences in the following forms

    http://oeis.org/A054531   (etc)

    A054531  - Y coordinate, ie. denominators

SEE ALSO

Math::PlanePath, Math::PlanePath::DiagonalRationals, Math::PlanePath::RationalsTree, Math::PlanePath::CoprimeColumns, Math::PlanePath::DiagonalsOctant

HOME PAGE

http://user42.tuxfamily.org/math-planepath/index.html

LICENSE

Copyright 2011, 2012 Kevin Ryde

This file is part of Math-PlanePath.

Math-PlanePath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

Math-PlanePath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Math-PlanePath. If not, see <http://www.gnu.org/licenses/>.