++ed by:
Kevin Ryde
and 1 contributors

# NAME

Math::PlanePath::PyramidRows -- points stacked up in a pyramid

# SYNOPSIS

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

# DESCRIPTION

This path arranges points in successively wider rows going upwards so as to form an upside-down pyramid. The default step is 2, ie. each row 2 wider than the preceding, an extra point at the left and the right,

``````    17  18  19  20  21  22  23  24  25         4
10  11  12  13  14  15  16             3
5   6   7   8   9                 2
2   3   4                     1
1                   <-  Y=0

-4  -3  -2  -1  X=0  1   2   3   4 ...``````

The right end N=1,4,9,16,etc is the perfect squares. The vertical 2,6,12,20,etc at x=-1 is the pronic numbers s*(s+1), half way between those successive squares.

The step 2 is the same as the `PyramidSides`, `Corner` and `SacksSpiral` paths. For the `SacksSpiral`, spiral arms going to the right correspond to diagonals in the pyramid, and arms to the left correspond to verticals.

## Step Parameter

A `step` parameter controls how much wider each row is than the preceding, to make wider pyramids. For example step 4

``    my \$path = Math::PlanePath::PyramidRows->new (step => 4);``

makes each row 2 wider on each side successively

``````   29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45        4
16 17 18 19 20 21 22 23 24 25 26 27 28              3
7  8  9 10 11 12 13 14 15                    2
2  3  4  5  6                          1
1                          <-  Y=0

-6 -5 -4 -3 -2 -1 X=0 1  2  3  4  5  6 ...``````

If the step is an odd number then the extra is at the right, so step 3 gives

``````    13  14  15  16  17  18  19  20  21  22        3
6   7   8   9  10  11  12                2
2   3   4   5                        1
1                          <-  Y=0

-3  -2  -1  X=0  1   2   3   4 ...``````

Or step 1 goes solely to the right. This is equivalent to the Diagonals path, but columns shifted up to make horizontal rows.

``````    step => 1

11  12  13  14  15                4
7   8   9  10                    3
4   5   6                        2
2   3                            1
1                          <-  Y=0

X=0  1   2   3   4 ...``````

Step 0 means simply a vertical, each row 1 wide and not increasing. This is unlikely to be much use. The Rows path with `width` 1 does this too.

``````    step => 0

5        4
4        3
3        2
2        1
1    <-y=0

X=0``````

Various number sequences fall in regular patterns positions depending on the step. Large steps are not particularly interesting and quickly become very wide. A limit might be desirable in a user interface, but there's no limit in the code as such.

## Align Parameter

An optional `align` parameter controls how the points are arranged relative to the Y axis. The default shown above is "centre".

"right" means points to the right of the axis,

``````    align=>"right"

26  27  28  29  30  31  32  33  34  35  36        5
17  18  19  20  21  22  23  24  25                4
10  11  12  13  14  15  16                        3
5   6   7   8   9                                2
2   3   4                                        1
1                                            <- Y=0

X=0  1   2   3   4   5   6   7   8   9  10``````

"left" is similar but to the left of the Y axis, ie. into negative X.

``````    align=>"left"

26  27  28  29  30  31  32  33  34  35  36        5
17  18  19  20  21  22  23  24  25        4
10  11  12  13  14  15  16        3
5   6   7   8   9        2
2   3   4        1
1    <- Y=0

-10 -9  -8  -7  -6  -5  -4  -3  -2  -1  X=0``````

The step parameter still controls how much longer each row is than its predecessor.

## N Start

The default is to number points starting N=1 as shown above. An optional `n_start` can give a different start, in the same rows sequence. For example to start at 0,

``````    n_start => 0

16 17 18 19 20 21 22 23 24        4
9 10 11 12 13 14 15           3
4  5  6  7  8              2
1  2  3                 1
0                <- Y=0
--------------------------
-4 -3 -2 -1 X=0 1  2  3  4``````

## Step 3 Pentagonals

For step=3 the pentagonal numbers 1,5,12,22,etc, P(k) = (3k-1)*k/2, are at the rightmost end of each row. The second pentagonal numbers 2,7,15,26, S(k) = (3k+1)*k/2 are the vertical at x=-1. Those second numbers are obtained by P(-k), and the two together are the "generalized pentagonal numbers".

Both these sequences are composites from 12 and 15 onwards, respectively, and the immediately preceding P(k)-1, P(k)-2, and S(k)-1, S(k)-2 are too. They factorize simply as

``````    P(k)   = (3*k-1)*k/2
P(k)-1 = (3*k+2)*(k-1)/2
P(k)-2 = (3*k-4)*(k-1)/2
S(k)   = (3*k+1)*k/2
S(k)-1 = (3*k-2)*(k+1)/2
S(k)-2 = (3*k+4)*(k-1)/2``````

Plotting the primes on a step=3 `PyramidRows` has the second pentagonal S(k),S(k)-1,S(k)-2 as a 3-wide vertical gap of no primes at X=-1,-2,-3. The the plain pentagonal P(k),P(k-1),P(k)-2 are the endmost three N of each row non-prime. The vertical is much more noticeable in a plot.

``````       no primes these three columns         no primes these end three
except the low 2,7,13                     except low 3,5,11
|  |  |                                /  /  /
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
23 24 25 26 27 28 29 30 31 32 33 34 35
13 14 15 16 17 18 19 20 21 22
6  7  8  9 10 11 12
2  3  4  5
1
-6 -5 -4 -3 -2 -1 X=0 1  2  3  4  5  6  7  8  9 10 11 ...``````

With align="left" the end values can be put into columns,

``````                                no primes these end three
align => "left"                  except low 3,5,11
|  |  |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51        5
23 24 25 26 27 28 29 30 31 32 33 34 35        4
13 14 15 16 17 18 19 20 21 22        3
6  7  8  9 10 11 12        2
2  3  4  5        1
1    <- Y=0
... -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 X=0``````

In general a constant offset S(k)-c is a column and from P(k)-c is a diagonal sloping up dX=2,dY=1 right. The simple factorizations above using the roots of the quadratic P(k)-c or S(k)-c is possible whenever 24*c+1 is a perfect square. This means the further columns S(k)-5, S(k)-7, S(k)-12, etc also have no primes.

The columns S(k), S(k)-1, S(k)-2 are prominent because they're adjacent. There's no other adjacent columns of this type because the squares after 49 are too far apart for 24*c+1 to be a square for successive c. Of course there could be other reasons for other columns or diagonals to have few or many primes.

# FUNCTIONS

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

`\$path = Math::PlanePath::PyramidRows->new ()`
`\$path = Math::PlanePath::PyramidRows->new (step => \$integer, align => \$str, n_start => \$n)`

Create and return a new path object. The default `step` is 2. `align` is a string, one of

``````    "centre"    the default
"right"     points aligned right of the Y axis
"left"      points aligned left of the Y axis``````

Points are always numbered from left to right in the rows, the alignment changes where each row begins (or ends).

`(\$x,\$y) = \$path->n_to_xy (\$n)`

Return the X,Y coordinates of point number `\$n` on the path.

For `\$n <= 0` the return is an empty list since the path starts at N=1.

`\$n = \$path->xy_to_n (\$x,\$y)`

Return the point number for coordinates `\$x,\$y`. `\$x` and `\$y` are each rounded to the nearest integer, which has the effect of treating each point in the pyramid as a square of side 1. If `\$x,\$y` is outside the pyramid the return is `undef`.

`(\$n_lo, \$n_hi) = \$path->rect_to_n_range (\$x1,\$y1, \$x2,\$y2)`

The returned range is exact, meaning `\$n_lo` and `\$n_hi` are the smallest and biggest in the rectangle.

## Descriptive Methods

`\$x = \$path->sumxy_minimum()`
`\$x = \$path->sumxy_maximum()`

Return the minimum or maximum values taken by coordinate sum X+Y reached by integer N values in the path. If there's no minimum or maximum then return `undef`.

The path is right and above the X=-Y diagonal, thus giving a minimum sum, in the following cases.

``````    align      condition for sumxy_minimum=0
------     -----------------------------
centre              step <= 3
right               always
left                step <= 1``````
`\$x = \$path->diffxy_minimum()`
`\$x = \$path->diffxy_maximum()`

Return the minimum or maximum values taken by coordinate difference X-Y reached by integer N values in the path. If there's no minimum or maximum then return `undef`.

The path is left and above the X=Y leading diagonal, thus giving a minimum X-Y difference, in the following cases.

``````    align      condition for diffxy_minimum=0
------     -----------------------------
centre              step <= 2
right               step <= 1
left                always``````

# OEIS

Entries in Sloane's Online Encyclopedia of Integer Sequences related to this path include

``````    step=1
A002262    X coordinate, runs 0 to k
A003056    Y coordinate, k repeated k+1 times
A051162    X+Y sum
A025581    Y-X diff, runs k to 0
A079904    X*Y product
A069011    X^2+Y^2, n_to_rsquared()
A080099    X bitwise-AND Y
A080098    X bitwise-OR  Y
A051933    X bitwise-XOR Y
A050873    GCD(X+1,Y+1) greatest common divisor by rows
A051173    LCM(X+1,Y+1) least common multiple by rows

A023531    dY, being 1 at triangular numbers (but starting n=0)
A167407    dX-dY, change in X-Y (extra initial 0)
A129184    turn 1=left, 0=right or straight

A079824    N total along each opposite diagonal
A000124    N on Y axis (triangular+1)
A000217    N on X=Y diagonal, extra initial 0
step=1, n_start=0
A109004    GCD(X,Y) greatest common divisor starting (0,0)
A103451    turn 1=left or right,0=straight, but extra initial 1
A103452    turn 1=left,0=straight,-1=right, but extra initial 1

step=2
A196199    X coordinate, runs -n to +n
A000196    Y coordinate, n appears 2n+1 times
A053186    X+Y, being distance to next higher square
A010052    dY,  being 1 at perfect square row end
A000290    N on X=Y diagonal, extra initial 0
A002522    N on X=-Y North-West diagonal (start row), Y^2+1
A004201    N for which X>=0, ie. right hand half
A020703    permutation N at -X,Y
step=2, n_start=0
A005563    N on X=Y diagonal, Y*(Y+2)
A000290    N on X=-Y North-West diagonal (start row), Y^2
step=2, n_start=2
A059100    N on north-west diagonal (start each row), Y^2+2
A053615    abs(X), runs k..0..k
step=2, align=right, n_start=0
A196199    X-Y, runs -k to +k
A053615    abs(X-Y), runs k..0..k
step=2, align=left, n_start=0
A005563    N on Y axis, Y*(Y+2)

step=3
A180447    Y coordinate, n appears 3n+1 times
A104249    N on Y axis, Y*(3Y+1)/2+1
A143689    N on X=-Y North-West diagonal
step=3, n_start=0
A005449    N on Y axis, second pentagonals Y*(3Y+1)/2
A000326    N on diagonal north-west, pentagonals Y*(3Y-1)/2

step=4
A084849    N on Y axis
A001844    N on X=Y diagonal (North-East)
A058331    N on X=-Y North-West diagonal
A221217    permutation N at -X,Y
step=4, n_start=0
A014105    N on Y axis, the second hexagonal numbers
A046092    N on X=Y diagonal, 4*triangular numbers
step=4, align=right, n_start=0
A060511    X coordinate, amount n exceeds hexagonal number
A000384    N on Y axis, the hexagonal numbers
A001105    N on X=Y diagonal, 2*squares

step=5
A116668    N on Y axis

step=6
A056108    N on Y axis
A056109    N on X=Y diagonal (North-East)
A056107    N on X=-Y North-West diagonal

step=8
A053755    N on X=-Y North-West diagonal

step=9
A006137    N on Y axis
A038764    N on X=Y diagonal (North-East)``````

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