.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Math::PlanePath::GcdRationals 3pm" .TH Math::PlanePath::GcdRationals 3pm "2021-01-23" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Math::PlanePath::GcdRationals \-\- rationals by triangular GCD .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 3 \& use Math::PlanePath::GcdRationals; \& my $path = Math::PlanePath::GcdRationals\->new; \& my ($x, $y) = $path\->n_to_xy (123); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This path enumerates X/Y rationals using a method by Lance Fortnow taking a greatest common divisor out of a triangular position. .IX Xref "Fortnow, Lance" .Sp .RS 4 .RE .PP The attraction of this approach is that it's both efficient to calculate and visits blocks of X/Y rationals using a modest range of N values, roughly a square N=2*max(num,den)^2 in the default rows style. .PP .Vb 10 \& 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 .Ve .PP The mapping from N to rational is .PP .Vb 3 \& N = i + j*(j\-1)/2 for upper triangle 1 <= i <= j \& gcd = GCD(i,j) \& rational = i/j + gcd\-1 .Ve .PP which means X=numerator Y=denominator are .PP .Vb 2 \& X = (i + j*(gcd\-1))/gcd = j + (i\-j)/gcd \& Y = j/gcd .Ve .PP The i,j position is a numbering of points above the X=Y diagonal by rows in the style of Math::PlanePath::PyramidRows with step=1, but starting from i=1,j=1. .PP .Vb 6 \& j=4 | 7 8 9 10 \& j=3 | 4 5 6 \& j=2 | 2 3 \& j=1 | 1 \& +\-\-\-\-\-\-\-\-\-\-\-\-\- \& i=1 2 3 4 .Ve .PP If \s-1GCD\s0(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. .PP The skipped positions where i,j have a common factor become rationals X/Y>1, ie. below the X=Y diagonal. The integer part is \s-1GCD\s0(i,j)\-1 so rational = gcd\-1 + i/j. For example .PP .Vb 4 \& N=51 is at i=6,j=10 by rows \& common factor gcd(6,10)=2 \& so rational R = 2\-1 + 6/10 = 1+3/5 = 8/5 \& ie. X=8,Y=5 .Ve .PP If j is prime then gcd(i,j)=1 and so X=i,Y=j. This means that in rows with prime Y are numbered by consecutive N across to the X=Y diagonal. For example in row Y=7 above N=22 to N=27. .SS "Triangular Numbers" .IX Subsection "Triangular Numbers" N=1,3,6,10,etc along the bottom Y=1 row is the triangular numbers N=k*(k\-1)/2. Such an N is at i=k,j=k and has gcd(i,j)=k which divides out to Y=1. .IX Xref "Triangular numbers" .PP .Vb 1 \& N=k*(k\-1)/2 i=k,j=k \& \& 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 .Ve .PP N=1,2,4,7,11,etc in the column at X=1 immediately follows each of those bottom row triangulars, ie. N+1. .PP .Vb 1 \& N in X=1 column = Y*(Y\-1)/2 + 1 .Ve .SS "Primes" .IX Subsection "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 \*(L"...\*(R" marking the X=2*Y line. .PP .Vb 10 \& 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 only \& | .... 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 .Ve .PP 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. The rest of the line X=2*k,Y=k is not visited since common factor k would mean X/Y is not a rational in least terms. .PP This pattern of primes and composites occurs because N is a multiple of gcd(i,j) when that gcd is odd, or a multiple of gcd/2 when that gcd is even. .PP .Vb 2 \& 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 .Ve .PP If gcd odd then either j/gcd or j\-1 is even, to take the \*(L"/2\*(R" divisor. If gcd even then only gcd/2 can come out as a factor since taking out the full gcd might leave both j/gcd and j\-1 odd and so the \*(L"/2\*(R" not an integer. That happens for example to N=70 .PP .Vb 4 \& 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 .Ve .PP Of course knowing gcd or gcd/2 is a factor of N is only useful when that factor is 2 or more, so .PP .Vb 2 \& odd gcd >= 2 means gcd >= 3 \& even gcd with gcd/2 >= 2 means gcd >= 4 \& \& so N composite when gcd(i,j) >= 3 .Ve .PP If gcd<3 then the \*(L"factor\*(R" coming out is only 1 and says nothing about whether N is prime or composite. There are both prime and composite N with gcd<3, as can be seen among the values above the X=2*Y line in the table above. .SS "Rows Reverse" .IX Subsection "Rows Reverse" Option \f(CW\*(C`pairs_order => "rows_reverse"\*(C'\fR reverses the order of points within the rows of i,j pairs, .PP .Vb 6 \& j=4 | 10 9 8 7 \& j=3 | 6 5 4 \& j=2 | 3 2 \& j=1 | 1 \& +\-\-\-\-\-\-\-\-\-\-\-\- \& i=1 2 3 4 .Ve .PP The X,Y numbering becomes .PP .Vb 1 \& 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 .Ve .PP The triangular numbers, per \*(L"Triangular Numbers\*(R" above, are now in the X=1 column, ie. at the left rather than at the Y=1 bottom row. That bottom row is now the next after each triangular, ie. T(X)+1. .SS "Diagonals" .IX Subsection "Diagonals" Option \f(CW\*(C`pairs_order => "diagonals_down"\*(C'\fR takes the i,j pairs by diagonals down from the Y axis. \f(CW\*(C`pairs_order => "diagonals_up"\*(C'\fR likewise but upwards from the X=Y centre up to the Y axis. (These numberings are in the style of Math::PlanePath::DiagonalsOctant.) .PP .Vb 1 \& 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 .Ve .PP The resulting path becomes .PP .Vb 1 \& 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 .Ve .PP The Y=1 bottom row is the perfect squares which are at i=j in the \f(CW\*(C`DiagonalsOctant\*(C'\fR and have gcd(i,j)=i thus becoming X=i,Y=1. .IX Xref "Square numbers" .PP .Vb 1 \& 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 .Ve .PP N=1,2,4,6,9 etc in the X=1 column is the perfect squares k*k and the pronics k*(k+1) interleaved, also called the quarter-squares. N=2,5,10,17,etc on Y=X+1 above the leading diagonal are the squares+1, and N=3,8,15,24,etc below on Y=X\-1 below the diagonal are the squares\-1. .IX Xref "Square numbers Pronic numbers Quarter square numbers" .PP The \s-1GCD\s0 division moves points downwards and shears them across horizontally. The effect on diagonal lines of i,j points is as follows .PP .Vb 10 \& | 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 \& +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- .Ve .PP The line of \*(L"1\*(R"s is the diagonal with gcd=1 and thus X,Y=i,j unchanged. .PP The line of \*(L"2\*(R"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. vertical. .PP Then gcd=3 becomes X=(i+2j)/3 which slopes across by +1 for each i, or gcd=4 has X=(i+3j)/4 slope +2, etc. .PP Of course only some of the points in an i,j 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 \*(L"*\*(R" points in the following are traversed, plus extras in wedge shaped arms out to the side. .PP .Vb 10 \& | * \& | * * up to a given diagonal points "*" \& | * * * all visited, plus some wedges out \& | * * * * to the right \& | * * * * * \& | * * * * * / \& | * * * * * / \-\- \& | * * * * * \-\- \& | * * * * *\-\- \& +\-\-\-\-\-\-\-\-\-\-\-\-\-\- .Ve .PP In terms of the rationals X/Y the effect is that up to N=d^2 with diagonal d=2j the fractions enumerated are .PP .Vb 2 \& N=d^2 \& enumerates all num/den where num <= d and num+den <= 2*d .Ve .SH "FUNCTIONS" .IX Header "FUNCTIONS" See \*(L"\s-1FUNCTIONS\*(R"\s0 in Math::PlanePath for behaviour common to all path classes. .ie n .IP """$path = Math::PlanePath::GcdRationals\->new ()""" 4 .el .IP "\f(CW$path = Math::PlanePath::GcdRationals\->new ()\fR" 4 .IX Item "$path = Math::PlanePath::GcdRationals->new ()" .PD 0 .ie n .IP """$path = Math::PlanePath::GcdRationals\->new (pairs_order => $str)""" 4 .el .IP "\f(CW$path = Math::PlanePath::GcdRationals\->new (pairs_order => $str)\fR" 4 .IX Item "$path = Math::PlanePath::GcdRationals->new (pairs_order => $str)" .PD Create and return a new path object. The \f(CW\*(C`pairs_order\*(C'\fR option can be .Sp .Vb 4 \& "rows" (default) \& "rows_reverse" \& "diagonals_down" \& "diagonals_up" .Ve .SH "FORMULAS" .IX Header "FORMULAS" .SS "X,Y to N \*(-- Rows" .IX Subsection "X,Y to N Rows" The defining formula above for X,Y can be inverted to give i,j and N. This calculation doesn't notice if X,Y have a common factor, so a coprime(X,Y) test must be made separately if necessary (for \f(CW\*(C`xy_to_n()\*(C'\fR it is). .PP .Vb 1 \& X/Y = g\-1 + (i/g)/(j/g) .Ve .PP The g\-1 integer part is recovered by a division X divide Y, .PP .Vb 5 \& X = quot*Y + rem division by Y rounded towards 0 \& where 0 <= rem < Y \& unless Y=1 in which case use quot=X\-1, rem=1 \& g\-1 = quot \& g = quot+1 .Ve .PP The Y=1 special case can instead be left as the usual kind of division quot=X,rem=0, so 0<=rem (etc) .RE .PP .Vb 7 \& pairs_order="rows" (the default) \& A226314 X coordinate \& A054531 Y coordinate, being N/GCD(i,j) \& A000124 N in X=1 column, triangular+1 \& A050873 ceil(X/Y), gcd by rows \& A050873\-A023532 floor(X/Y) \& gcd by rows and subtract 1 unless i=j \& \& pairs_order="diagonals_down" \& A033638 N in X=1 column, quartersquares+1 and pronic+1 \& A000290 N in Y=1 row, perfect squares \& \& pairs_order="diagonals_up" \& A002620 N in X=1 column, squares and pronics \& A002061 N in Y=1 row, central polygonals (extra initial 1) \& A002522 N at Y=X+1 above leading diagonal, squares+1 .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" Math::PlanePath, Math::PlanePath::DiagonalRationals, Math::PlanePath::RationalsTree, Math::PlanePath::CoprimeColumns, Math::PlanePath::DiagonalsOctant .SH "HOME PAGE" .IX Header "HOME PAGE" .SH "LICENSE" .IX Header "LICENSE" Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Kevin Ryde .PP This file is part of Math-PlanePath. .PP Math-PlanePath is free software; you can redistribute it and/or modify it under the terms of the \s-1GNU\s0 General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. .PP Math-PlanePath is distributed in the hope that it will be useful, but \&\s-1WITHOUT ANY WARRANTY\s0; without even the implied warranty of \s-1MERCHANTABILITY\s0 or \s-1FITNESS FOR A PARTICULAR PURPOSE.\s0 See the \s-1GNU\s0 General Public License for more details. .PP You should have received a copy of the \s-1GNU\s0 General Public License along with Math-PlanePath. If not, see .