Math::...veStair(3pm)

πŸ“¦
version 129 Β· 3 versions
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸŽ€ NAME πŸŽ€

Hiii bestie πŸ’– welcome to the Math::...veStair(3pm) page β€” yep, that's the User Contributed Perl Documentation corner of the internet, and the star of the show is Math::PlanePath::SierpinskiCurveStair, aka the Sierpinski curve but make the diagonals stair-step. That's it, that's the whole assignment. πŸ‘‘


✨ SYNOPSIS ✨

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

πŸ’– DESCRIPTION πŸ’–

Okay so this is a remix of the "SierpinskiCurve", except every diagonal bit gets chopped into little stair steps β€” horizontal then vertical, no shortcuts. Look at her go πŸ˜­πŸ’…

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

The tiling? Literally the same as the "SierpinskiCurve", bestie β€” only the diagonals become a stair step, one horizontal plus one vertical. The correspondence goes like:

   SierpinskiCurve        SierpinskiCurveStair

               7--                   12--
             /                        |
            6                     10-11
            |                      |
            5                      9--8
             \                        |
      1--2     4             2--3  6--7
    /     \  /               |  |  |
   0        3             0--1  4--5

So the "SierpinskiCurve" N=0 to N=3 maps onto N=0 to N=5 over here. Then N=7 to N=12 is a whole copy of that N=0 to N=5 base. And point N=6? That's the little extra sitting between the parts. The next extra one of those is N=19. πŸ™ˆ

πŸ¦‹ Diagonal Length πŸ¦‹

The "diagonal_length" option lets you make the diagonals longer β€” still stair-step styled, obviously, we don't break the theme. Like:

            diagonal_length => 4
   10  |                                 36-37
       |                                  |  |
    9  |                              34-35 38-39
       |                               |        |
    8  |                           32-33       40-41
       |                            |              |
    7  |                        30-31             42-43
       |                         |                    |
    6  |                     28-29                   44-45
       |                      |                          |
    5  |                     27-26                   47-46
       |                         |                    |
    4  |                8--9    25-24             49-48    ...
       |                |  |        |              |        |
    3  |             6--7 10-11    23-22       51-50    62-63
       |             |        |        |        |        |
    2  |          4--5       12-13    21-20 53-52    60-61
       |          |              |        |  |        |
    1  |       2--3             14-15 18-19 54-55 58-59
       |       |                    |  |        |  |
   Y=0 |    0--1                   16-17       56-57
       |
       +------------------------------------------------------
         ^
        X=0 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17

The length is reckoned from N=0 to the end of the first side at N=8, which runs X=1 to X=5 when the length is 4 units. Math is mathing. ✨

🌈 Arms 🌈

The optional "arms" parameter can give you up to eight copies of the curve, each one advancing successively. Eight! The audacity. 😭 For example:

   arms => 8

      98-90 66-58       57-65 89-97            5
          |  |  |        |  |  |
   99    82-74 50-42 41-49 73-81    96         4
    |              |  |              |
   91-83       26-34 33-25       80-88         3
       |        |        |        |
   67-75       18-10  9-17       72-64         2
    |              |  |              |
   59-51 27-19     2  1    16-24 48-56         1
       |  |  |              |  |  |
      43-35 11--3     .  0--8 32-40       <- Y=0

      44-36 12--4        7-15 39-47           -1
       |  |  |              |  |  |
   60-52 28-20     5  6    23-31 55-63        -2
    |              |  |              |
   68-76       21-13 14-22       79-71        -3
       |        |        |        |
   92-84       29-37 38-30       87-95        -4
                   |  |
         85-77 53-45 46-54 78-86              -5
          |  |  |        |  |  |
         93 69-61       62-70 94              -6

                      ^
   -6 -5 -4 -3 -2 -1 X=0 1  2  3  4  5  6

The multiples of 8 (or however many arms you picked) β€” N=0, 8, 16, etc β€” that's the original curve, and everything mod 8 beyond that is one of the copies.

The little . in the middle there is the origin at X=0,Y=0. It would be more symmetrical to shove the origin into the middle of the eight arms (that'd be X=-0.5,Y=-0.5 in the picture above), but nooo, that would hand you fractional X,Y values and we don't do that here. Apply an offset of X+0.5,Y+0.5 if you want it centred. Slay. πŸ’…

πŸ‘‘ Level Ranges πŸ‘‘

N=0 is reckoned as level=0, then N=0 to N=5 inclusive is level=1, and so on up forever. Each level is 4 copies of the previous one, plus 2 extra points in between. πŸ’€

   LevelPoints[k] = 4*LevelPoints[k-1] + 2   starting LevelPoints[0]=1
                  = 2 + 2*4 + 2*4^2 + ... + 2*4^(k-1) + 1*4^k
                  = (5*4^k - 2)/3

   Nlevel[k] = LevelPoints[k] - 1         since starting at N=0
             = 5*(4^k - 1)/3
             = 0, 5, 25, 105, 425, 1705, 6825, 27305, ...    (A146882)

The width along the X axis of a level doubles each time, plus an extra distance of 3 in between:

   LevelWidth[k] = 2*LevelWidth[k-1] + 3     starting LevelWidth[0]=0
                 = 3 + 3*2 + 3*2^2 + ... + 3*2^(k-1) + 0*2^k
                 = 3*(2^k - 1)

   Xlevel[k] = 1 + LevelWidth[k]
             = 3*2^k - 2
             = 1, 4, 10, 22, 46, 94, 190, 382, ...           (A033484)

🧚 Level Ranges with Diagonal Length 🧚

When "diagonal_length" = L, level=0 is reckoned as having L many points instead of just the one:

   LevelPoints[k] = 2 + 2*4 + 2*4^2 + ... + 2*4^(k-1) + L*4^k
                  = ( (3L+2)*4^k - 2 )/3

   Nlevel[k] = LevelPoints[k] - 1
             = ( (3L+2)*4^k - 5 )/3

And the width of level=0 becomes L-1 instead of 0:

   LevelWidth[k] = 2*LevelWidth[k-1] + 3     starting LevelWidth[0]=L-1
                 = 3 + 3*2 + 3*2^2 + ... + 3*2^(k-1) + (L-1)*2^k
                 = (L+2)*2^k - 3

   Xlevel[k] = 1 + LevelWidth[k]
             = (L+2)*2^k - 2

Think of level=0 with L many points as a cute little block that gets replicated in mirror image to build level=1. Like, the diagonal 4 example from earlier turns into:

                   8  9            diagonal_length => 4
                   |  |
                6--7 10-11
                |        |
             .  5       12  .

          2--3             14-15
          |                    |
       0--1                   16-17

The spacing between the parts in the tiling comes from taking a margin of 1/2 at the base and 1 horizontally on the left and right. 🫢

πŸ“ Level Fill πŸ“

Plot twist: the curve does not visit all the points in that eighth of the plane below the X=Y diagonal. Not even close. In general, Nlevel+1 many points get visited out of the triangular area Xlevel^2/4, so the filled fraction approaches a constant:

                     Nlevel          4*(3L+2)
       FillFrac = ------------   ->  ---------
                  Xlevel^2 / 4       3*(L+2)^2

For example, the default L=1 gives FillFrac=20/27=0.74. Or L=2 gives FillFrac=2/3=0.66. As the diagonal length grows, that fraction shrinks β€” because the holes in the pattern keep getting bigger. It's giving "more curve, more gaps". 🌸


πŸ›  FUNCTIONS πŸ› 

Go peek at "FUNCTIONS" in Math::PlanePath for all the behaviour that's common to every path class. πŸ’œ

  • $path = Math::PlanePath::SierpinskiCurveStair->new ()
  • $path = Math::PlanePath::SierpinskiCurveStair->new (diagonal_length => $L, arms => $A) β€” create and return a shiny new path object, bestie.
  • ($x,$y) = $path->n_to_xy ($n) β€” returns the X,Y coordinates of point number $n on the path. Points start at 0, and if "$n < 0" then you get an empty list back, sorry. 😭

Fractional positions give you an X,Y position along a straight line between the integer positions.

  • $n = $path->n_start() β€” returns 0, the first N in the path. Periodt.

πŸŽ€ Level Methods πŸŽ€

  • ($n_lo, $n_hi) = $path->level_to_n_range($level) β€” returns (0, ((3*$diagonal_length +2) * 4**$level - 5)/3 exactly as per "Level Ranges with Diagonal Length" up above. No cap. πŸ’…

πŸ”’ OEIS πŸ”’

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

   <http://oeis.org/A146882> (etc)

   A146882   Nlevel, for level=1 up
   A033484   Xmax and Ymax in level, being 3*2^n - 2

πŸ‘€ SEE ALSO πŸ‘€

  • Math::PlanePath
  • Math::PlanePath::SierpinskiCurve

🏠 HOME PAGE 🏠

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

βš–οΈ LICENSE βš–οΈ

Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Kevin Ryde

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/>.

ngl bestie, that warranty disclaimer is doing the most, but read it β€” no promises, no guarantees, that's the deal. πŸ™ˆ

okay that's the whole page, we ate and left zero crumbs πŸ‘‘βœ¨ this was perl v5.32.0, dated 2021-01-23, and it's the Math::...veStair(3pm) page β€” love that for us, bye bestie πŸ’–πŸ¦‹πŸŒΈ