ความสวยงามอย่างหนึ่งของใบเฟิร์น คือ รูปทรงของส่วนย่อยๆ ภายในใบจะมีความคล้ายคลึงกับใบเฟิร์นทั้งใบ ภาษาคณิตศาสตร์มีชื่อเรียกพิเศษให้รูปทรงเหล่านี้เลยว่า fractal แต่ถ้าใครคุ้นเคยกับศัพท์สายคอมพิวเตอร์มากกว่า ก็อาจจะมองว่ามันเป็น recursion ก็ได้
การสร้าง fractal รูปใบเฟิร์นอย่างง่าย สามารถอธิบายคร่าวๆ ได้ด้วยขั้นตอนวิธีนี้
- ลากเส้นตรงความยาว $l$ ไม่ต้องเยอะมากนัก แล้วเลือกปลายข้างหนึ่งไว้เป็นปลายที่จะต่อยอดออกไป
- ที่ปลายยอดของเส้นตั้งต้น ทำสองขั้นตอนต่อไปนี้เพื่อลากเส้นเพิ่ม 3 เส้น
- ลากเส้นตรงความยาว $0.2$ เท่าของความยาวเส้นตั้งต้น ในทิศทางตั้งฉากกับเส้นตั้งต้นทั้งสองข้าง
- ลากเส้นตรงความยาว $0.8$ เท่าของความยาวเส้นตั้งต้น ในทิศทางต่อขึ้นไปตรงๆ จากเส้นตั้งต้น
- สำหรับแต่ละเส้นที่ลากต่อออกมาในข้อ 2 นั้น เลือกปลายด้านที่ว่างๆ ไว้เป็นปลายต่อยอด แล้ววนกลับไปทำขั้นตอนที่ 2 โดยเปลี่ยนมาใช้เส้นตั้งต้นเป็นเส้นที่ได้จากข้อ 2 แทน (คิดซะว่าเส้นใหม่นี้ยาว $l$) ทำไปเรื่อยๆ จนกว่าจะพอใจผลลัพธ์
วิธีการข้างต้นจะให้ผลลัพธ์เป็นรูปใบเฟิร์นเรียบๆ ตรงๆ ไม่หวือหวานัก แต่ก็มีนักคณิตศาสตร์นามว่า Michael Barnsley ได้เขียนสมการกำหนดมุมและจัดตำแหน่งของการต่อยอดให้สวยงามมีลูกเล่น เนื่องจากเขาเป็นคนแรกที่เขียนเรื่องนี้ไว้ตั้งแต่ปี 1993 ทุกคนเลยพากันเรียกใบเฟิร์นที่สวยงามเป็นเอกลักษณ์นี้ว่า ใบเฟิร์น Barnsley
พูดให้รัดกุมเป็นภาษาคณิตศาสตร์ก็คือ การสร้างใบเฟิร์น Barnsley เริ่มจากลากเส้นแรกยาว $1.6$ หน่วยจากจุด $(0,0)$ ขึ้นไปตามแกน $y$ แล้วเอาเส้นนั้นมาวาดซ้ำๆ อีกครั้ง จากเลื่อนและปรับขนาดด้วยสมการดังนี้
f_1(x, y) = [ 0.85, 0.04; -0.04, 0.85 ] [ x; y ] + [ 0; 1.6 ] f_2(x, y) = [ 0.20 & -0.26 \\ 0.23 & 0.22 ] [ x; y ] + [ 0; 1.6 ] f_3(x, y) = [ -0.15, 0.28; 0.26 & 0.24 ] [ x; y ] + [ 0; 0.44 ]
โดย $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 ที่จะปรับขนาดตัวให้ไม่ใหญ่ไปกว่าก้านใบเฟิร์นที่ยืนอยู่ได้ แล้วก็ลองไปยืนอยู่บนใบเฟิร์นข้างต้นดู ณ ขณะหนึ่งเราอาจจะคิดว่าตัวเองอยู่บนก้านที่ใหญ่ที่สุดแล้ว แต่นอกจากขนาดที่แตกต่างกัน ก้านที่เราคิดว่าใหญ่ที่สุดนั้น ก็ไม่ได้มีอะไรที่แตกต่างจากก้านย่อยก้านอื่นๆ เลย หากเราเดินย้อนกลับไปเรื่อยๆ อาจพบว่าก้านที่เราคิดว่าใหญ่ที่สุดนั้น เป็นเพียงแค่ก้านย่อยที่แตกแขนงแยกออกมาก็เป็นได้
ในทางเดียวกัน เราก็ไม่สามารถแน่ใจได้ว่าตรงไหนคือจุดปลายของใบเฟิร์น เพราะยิ่งเดินค้นหาปลายใบเท่าไหร่ เราก็จะยิ่งตัวเล็กลงๆ และพบว่าใบเฟิร์นนั้นมีรูปร่างเหมือนเดิมไม่เปลี่ยนแปลง
ก็เปรียบเหมือนความรู้ เราจะรู้ได้ไงว่าอะไรคือพื้นฐานที่แท้จริงกันแน พันปีก่อนเราอาจคิดว่าถ้าได้รู้จักอะตอมก็คือรู้ถึงพื้นฐานแห่งทุกสรรพสิ่งแล้ว แต่ไม่กี่ร้อยปีก่อนเราเพิ่งพบว่าอะตอมยังแบ่งแยกย้อยลงไปได้อีกเป็นโปรตอน นิวตรอน อิเล็กตรอน และปฏิรูปพื้นฐานความรู้ด้านเคมีขึ้นใหม่ ส่วนปัจจุบันเรายังแบ่งย่อยสิ่งต่างๆ ลงไปได้อีกเป็นควาร์ก หรือแม้กระทั่งเสนอทฤษฎีสตริงซึ่งเป็นพื้นฐานของทุกอนุภาค
อีกนัยหนึ่ง พื้นฐานความรู้ที่ลึกเกินไปอาจเป็นสิ่งไม่จำเป็น หรือยิ่งไปกว่านั้น มันอาจเป็นตัวถ่วงให้เราไม่กล้าที่จะเดินหน้าสำรวจโลกใหม่ๆ ก็เป็นได้