วงแหวนเว็บ

neizod's speculation

insufficient data for meaningful answer

ใบเฟิร์น Barnsley

ความสวยงามอย่างหนึ่งของใบเฟิร์น คือ รูปทรงของส่วนย่อยๆ ภายในใบจะมีความคล้ายคลึงกับใบเฟิร์นทั้งใบ ภาษาคณิตศาสตร์มีชื่อเรียกพิเศษให้รูปทรงเหล่านี้เลยว่า fractal แต่ถ้าใครคุ้นเคยกับศัพท์สายคอมพิวเตอร์มากกว่า ก็อาจจะมองว่ามันเป็น recursion ก็ได้

การสร้าง fractal รูปใบเฟิร์นอย่างง่าย สามารถอธิบายคร่าวๆ ได้ด้วยขั้นตอนวิธีนี้

  1. ลากเส้นตรงตั้งต้นยาว $\ell$ แล้วเลือกปลายข้างหนึ่งไว้เป็นปลายที่จะต่อยอดออกไป
  2. ลากเส้นตรงเพิ่ม 3 เส้นที่มีปลายด้านหนึ่งอยู่บนเส้นตั้งต้น ดังนี้
    • ที่ปลายยอดของเส้นตั้งต้น ลากเส้นตรงยาว $0.7\ell$ ต่อขนานขึ้นไปตรงๆ
    • ที่ตรงกลางของเส้นตั้งต้น ลากเส้นตรงยาว $0.4\ell$ ตั้งฉากออกมาทั้งด้านซ้ายและขวา
  3. สำหรับแต่ละเส้นที่ลากต่อออกมาในข้อ 2 เลือกปลายด้านที่ว่างๆ ไว้เป็นปลายต่อยอด แล้ววนกลับไปทำขั้นตอนที่ 2 โดยเปลี่ยนมาใช้เส้นตั้งต้นเป็นเส้นที่ได้จากข้อ 2 แทน (คิดซะว่าเส้นใหม่นี้ยาว $\ell$) ทำไปเรื่อยๆ จนกว่าจะพอใจผลลัพธ์

ใบเฟิร์นอย่างง่ายจาก fractal

วิธีการข้างต้นจะให้ผลลัพธ์เป็นรูปใบเฟิร์นเรียบง่ายไม่หวือหวานัก (เอาจริงๆ ก็อาจจะดูไม่เหมือนใบเฟิร์นซักเท่าไหร่) จนกระทั่งมีนักคณิตศาสตร์นามว่า Michael Barnsley ได้เขียนสมการกำหนดมุมและจัดตำแหน่งของการต่อยอดให้สวยงามมีลูกเล่น เนื่องจากเขาเป็นคนแรกที่เขียนเรื่องนี้ไว้ตั้งแต่ปี 1993 ทุกคนเลยพากันเรียกใบเฟิร์นที่สวยงามเป็นเอกลักษณ์นี้ว่า ใบเฟิร์น Barnsley

ใบเฟิร์น Barnsley ที่ได้หลังจากการทำซ้ำ 23 รอบ

พูดให้รัดกุมเป็นภาษาคณิตศาสตร์ก็คือ การสร้างใบเฟิร์น Barnsley เริ่มจากลากเส้นแรกยาว $1.6$ หน่วยจากจุด $(0,0)$ ขึ้นไปตามแกน $y$ แล้วเอาเส้นนั้นมาวาดซ้ำๆ อีกครั้ง จากเลื่อนและปรับขนาดด้วยสมการดังนี้

\[\begin{align} f_1(x, y) &= \begin{bmatrix} 0.85 & 0.04 \\ -0.04 & 0.85 \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix} \\ f_2(x, y) &= \begin{bmatrix} 0.20 & -0.26 \\ 0.23 & 0.22 \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix} \\ f_3(x, y) &= \begin{bmatrix} -0.15 & 0.28 \\ 0.26 & 0.24 \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} 0 \\ 0.44 \end{bmatrix} \end{align}\]

โดย $f_1, f_2, f_3$ คือสมการสำหรับคำนวณรูปร่างก้านที่ต่อยอดขึ้นข้างบน ก้านที่เอียงไปด้านซ้าย และก้านที่พลิกตัวแล้วเอียงไปด้านขวา ตามลำดับ

ผมแนบโค้ดในภาษา Python มาให้ด้วยสำหรับใครที่ต้องการนำไปเล่นต่อ ซึ่งวิธีการที่แนบนี้เป็นการสร้างแบบ recursive ต่อยอดออกไปเรื่อยๆ ตามแนวทางขั้นตอนวิธีที่ได้กล่าวไว้ข้างต้น หากไปค้นดูวิธีอื่นเพิ่มเติมจะพบว่าวิธีการสุ่มเลือกจุดจะให้ผลลัพธ์ที่รวดเร็วกว่า

from PIL import Image, ImageDraw

def transform(matrix, xy):
    return [sum(e * p for e, p in zip(row, xy)) for row in matrix]

def translate(vector, xy):
    return [e + p for e, p in zip(vector, xy)]

class BarnsleyFern(object):
    affines = [([[0.85, 0.04], [-0.04, 0.85]], [0, 1.6]),
               ([[0.20, -0.26], [0.23, 0.22]], [0, 1.6]),
               ([[-0.15, 0.28], [0.26, 0.24]], [0, 0.44])]

    def __init__(self, depth=10, size=(800,800)):
        self.image = Image.new('RGB', size)
        self.draw = ImageDraw.Draw(self.image)
        self.iterate([0.0, 0.0], [0.0, 1.6], depth)

    def canvas_coordinate(self, xy):
        width, height = self.image.size
        return [width/2 + xy[0]*width/10, height - xy[1]*height/10]

    def linespec(self, xy0, xy1):
        return self.canvas_coordinate(xy0) + self.canvas_coordinate(xy1)

    def draw_too_small(self, xy0, xy1, pos=2):
        return all(round(a, pos) == round(b, pos) for a, b in zip(xy0, xy1))

    def iterate(self, xy0, xy1, depth, affine=None):
        if depth == 0:
            return
        if affine is not None:
            xy0 = translate(affine[1], transform(affine[0], xy0))
            xy1 = translate(affine[1], transform(affine[0], xy1))
        if self.draw_too_small(xy0, xy1):
            return
        self.draw.line(self.linespec(xy0, xy1), fill='#0C3')
        for affine in self.affines:
            self.iterate(xy0, xy1, depth-1, affine)

fractal ยังมีรูปร่างอื่นๆ อีกมากมาย ทั้งที่พบได้ในธรรมชาติ เช่น ดอกทานตะวัน บรอคโคลี เกล็ดหิมะ หรือมาจากการสังเคราะห์ขึ้นอย่าง สามเหลี่ยม Sierpinski หรือ เซต Mandelbrot

แต่ความมหัศจรรย์ของ fractal ที่แท้จริง คือเราไม่สามารถรู้ได้เลยว่าตอนนี้เรากำลังอยู่ตรงไหนของมันกันแน่ ลองคิดภาพว่าตัวเองเป็น Ant-Man ที่จะปรับขนาดตัวให้ไม่ใหญ่ไปกว่าก้านใบเฟิร์นที่ยืนอยู่ได้ แล้วก็ลองไปยืนอยู่บนใบเฟิร์นข้างต้นดู ณ ขณะหนึ่งเราอาจจะคิดว่าตัวเองอยู่บนก้านที่ใหญ่ที่สุดแล้ว แต่นอกจากขนาดที่แตกต่างกัน ก้านที่เราคิดว่าใหญ่ที่สุดนั้น ก็ไม่ได้มีอะไรที่แตกต่างจากก้านย่อยก้านอื่นๆ เลย หากเราเดินย้อนกลับไปเรื่อยๆ อาจพบว่าก้านที่เราคิดว่าใหญ่ที่สุดนั้น เป็นเพียงแค่ก้านย่อยที่แตกแขนงแยกออกมาก็เป็นได้

ในทางเดียวกัน เราก็ไม่สามารถแน่ใจได้ว่าตรงไหนคือจุดปลายของใบเฟิร์น เพราะยิ่งเดินค้นหาปลายใบเท่าไหร่ เราก็จะยิ่งตัวเล็กลงๆ และพบว่าใบเฟิร์นนั้นมีรูปร่างเหมือนเดิมไม่เปลี่ยนแปลง

ก็เปรียบเหมือนความรู้ เราจะรู้ได้ไงว่าอะไรคือพื้นฐานที่แท้จริงกันแน พันปีก่อนเราอาจคิดว่าถ้าได้รู้จักอะตอมก็คือรู้ถึงพื้นฐานแห่งทุกสรรพสิ่งแล้ว แต่ไม่กี่ร้อยปีก่อนเราเพิ่งพบว่าอะตอมยังแบ่งแยกย้อยลงไปได้อีกเป็นโปรตอน นิวตรอน อิเล็กตรอน และปฏิรูปพื้นฐานความรู้ด้านเคมีขึ้นใหม่ ส่วนปัจจุบันเรายังแบ่งย่อยสิ่งต่างๆ ลงไปได้อีกเป็นควาร์ก หรือแม้กระทั่งเสนอทฤษฎีสตริงซึ่งเป็นพื้นฐานของทุกอนุภาค

อีกนัยหนึ่ง พื้นฐานความรู้ที่ลึกเกินไปอาจเป็นสิ่งไม่จำเป็น หรือยิ่งไปกว่านั้น มันอาจเป็นตัวถ่วงให้เราไม่กล้าที่จะเดินหน้าสำรวจโลกใหม่ๆ ก็เป็นได้

neizod

author