Fraktal dengan Python. Panduan

Halo, Habr! Posting hari ini tentang fraktal telah tampil sebagai bagian dari tema Python , khususnya, Matplotlib. Ikuti contoh penulis dan ingatkan bahwa di pos ada banyak animasi berat yang bahkan mungkin tidak berfungsi di perangkat seluler. Tapi betapa cantiknya.



Semua senang membaca

Fraktal itu indah. Mereka berbaris sesuai dengan pola yang sangat kompleks dan dipertahankan tanpa distorsi pada pembesaran apapun! Pada artikel ini, kita akan melihat bagaimana Anda dapat dengan mudah menggambar fraktal dari beberapa jenis, menggunakan alat yang disebut L-Systems dan modul Turtle untuk Python untuk melakukan menggambar langkah-demi-langkah.

Dalam artikel ini, kami tidak akan membahas detail teknis secara berlebihan; sebagai gantinya, saya membatasi diri pada pengantar singkat, menunjukkan banyak contoh animasi dan kode yang dengannya Anda dapat menghasilkan contoh seperti itu. Jika Anda ingin melewatkan teorinya dan hanya menonton animasinya, langsung saja ke contohnya. Selain itu, pada bagian akhir saya akan menunjukkan beberapa sumber, baik dalam penulisan kode dan dalam matematika dasar, yang mungkin ingin Anda jelajahi.

Apa itu fraktal?

Untuk memulai, mari berikan definisi fraktal yang “longgar”. Pada prinsipnya, fraktal adalah angka geometris yang menunjukkan sifat yang sama terlepas dari tingkat kenaikannya.

Definisi ini tidak sempurna, jadi ini yang lebih akurat dari situs web Math World:
Fraktal adalah objek atau kuantitas yang menunjukkan kemiripan diri (dalam arti formal) pada skala apa pun. Sebuah objek tidak menunjukkan struktur yang identik pada skala yang berbeda, tetapi struktur dengan "tipe" yang sama harus muncul di semua tingkat fraktal. Dalam hal ini, grafik diplot dalam sistem koordinat dengan skala logaritmik, di mana besaran dan skala dihitung di sepanjang sumbu, grafik adalah garis lurus dengan kemiringan yang mencerminkan dimensi fraktal. - Dunia Matematika

Bagaimana cara menggambar fraktal menggunakan Python?

Biasanya, rendering fraktal adalah kompleks, karena sifat fraktal yang dalam ditentukan oleh konsep rekursi. Berbicara tentang grafik dan gambarnya, kita biasanya berpikir bahwa mereka dibentuk oleh piksel atau vektor, tetapi jumlah piksel atau vektor selalu terbatas, dan fraktal bersifat rekursif tanpa batas menurut definisi. Jadi, mencoba menerapkan fraktal ke kisi koordinat, kita harus berhenti di beberapa titik, dan itulah sebabnya kita berbicara tentang "iterasi" dalam kasus ini. Pada setiap iterasi, fraktal menjadi lebih rumit, dan pada titik tertentu menjadi tidak mungkin untuk membedakan dua iterasinya mengikuti satu sama lain (momen seperti itu terjadi ketika perubahan terjadi pada tingkat yang sebanding dengan ukuran piksel). Adalah logis untuk berhenti di sini, tetapi, sebagai suatu peraturan, bentuk fraktal tampak lebih cepat, dan Anda dapat berhenti lebih awal.

Dua contoh tersebut adalah pulau persegi Koch, yang strukturnya jelas muncul setelah tiga iterasi, dan naga Carter-Heitway, yang 8 iterasi cukup untuk membangun struktur yang lengkap. Jumlah iterasi yang diperlukan sangat tergantung pada fraktal spesifik yang sedang kami kerjakan.

Tentu saja, ada banyak perpustakaan Python untuk dipetakan, di antaranya yang paling populer adalah Matplotlib, tetapi mereka biasanya dirancang untuk menggambar statistik dan menggambar grafik yang terkenal. Secara khusus, Matplotlib berisi beberapa konstruksi tingkat rendah yang dapat digunakan untuk membangun fraktal, tetapi kali ini kita akan fokus pada modul yang kurang dikenal dari perpustakaan standar yang disebut Turtle.

Modul Turtle

dalam dokumentasi Pythonkita membaca: “Grafis penyu adalah alat yang populer untuk kenalan pertama anak-anak dengan pemrograman. Dia adalah bagian dari bahasa pemrograman Logo asli, yang dikembangkan oleh Wally Förzeg dan Seymour Papert pada tahun 1966. ”

Intinya adalah bahwa kura-kura mengenali 3 perintah secara default:

  • Merayap maju
  • Putar Sudut Kiri
  • Putar Sudut Kanan

Catatan: perintah lain disediakan di pustaka standar, tetapi di sini kita hanya akan menggunakan ketiga perintah ini.

Kami juga dapat:

  • Bisukan rekaman
  • Aktifkan perekaman

Karakteristik ini tampaknya terlalu sederhana untuk menggambar pada grafik yang rumit seperti fraktal, hanya mengandalkan mereka, tetapi kita akan menggunakan alat lain yang hanya menggunakan set instruksi kecil ini. Saya berbicara tentang L-sistem.

Sistem-

L Sistem-L adalah cara untuk merepresentasikan struktur rekursif (misalnya, fraktal) sebagai string karakter dan menulis ulang string seperti itu beberapa kali. Sekali lagi, kami memberikan definisi formal:
Sistem Lindenmeyer, juga dikenal sebagai sistem-L, adalah mekanisme penulisan ulang garis yang dapat digunakan untuk menghasilkan fraktal dengan dimensi dari 1 hingga 2 - Dunia Matematika

Setelah memahami apa itu sistem-L, kita dapat membuat struktur rekursif, tetapi pertama-tama, mari kita cari tahu komponen apa yang kita butuhkan untuk ini. Setiap L-sistem memiliki:

  • : , L-.
  • : .
  • : , .

Catatan untuk penggemar Ilmu Komputer: Jika Anda telah mempelajari Ilmu Komputer secara mendalam, maka semua hal di atas dapat mengingatkan Anda tentang sesuatu. Memang, tata bahasa formal didefinisikan sangat mirip; perbedaan utama adalah bahwa, tidak seperti tata bahasa, di sini pada setiap iterasi sebanyak mungkin aturan berlaku, dan bukan hanya satu. Oleh karena itu, L-sistem adalah bagian dari tata bahasa bebas konteks.

Mengingat bahwa kita akan menggunakan Turtle untuk membuat grafik dan sistem-L untuk mewakili apa yang akan kita plot, kita perlu membuat hubungan di antara mereka.

Karena di Turtle kita hanya memiliki tim yang terdaftar di atas, kita menetapkan masing-masing dari mereka simbol; alfabet akan terdiri dari karakter-karakter ini.

  • F: merangkak ke depan
  • +: belok kanan
  • -: belok kiri

Agar ini berfungsi, sudut harus disediakan untuk setiap fraktal; ini akan menjadi sudut di mana kura-kura akan berbelok ke kanan atau ke kiri. Untuk kesederhanaan, kami setuju bahwa hanya satu sudut yang harus disediakan, dan kami akan menulis sistem-L, mengingat hal ini.
Aksioma dan instruksi untuk membuat string hanya akan bergantung pada fraktal, tetapi fraktal harus ditulis sehingga hanya dapat diwakili oleh tiga karakter ini. Jadi ada batasan, berdasarkan yang kita hanya dapat membangun fraktal garis tunggal, yaitu, sesuatu seperti set Cantor tidak dapat diperoleh dengan cara ini. Tapi ini hanya penyederhanaan, karena kita selalu dapat memasukkan dua perintah lain untuk bergerak maju tanpa merekam, dan yang sama untuk bergerak mundur.

Sekarang mari kita ke contoh!

Contoh Animasi Contoh

berikut diambil secara online dari beberapa sumber yang tersedia untuk umum, dan saya memutuskan untuk port mereka ke Python menggunakan modul Turtle, pusatkan mereka, pewarnaan mereka, dan menyediakan cara untuk mengekspor ke format vektor.

PERHATIAN: animasi yang diusulkan cukup besar, disarankan untuk menontonnya hanya dengan internet yang bagus. Kode Repl mungkin tidak berfungsi karena menghabiskan sumber daya Anda, dan mungkin ada masalah dengan menampilkan fraktal pada perangkat seluler.

Catatan: Memahat menggunakan BROWSER ANDA untuk membuat dan membuat animasi, jadi ketika Anda menggantung, lag atau perilaku aneh, biasanya cukup hanya dengan memutar ulang animasi atau memuat ulang halaman. Mungkin tidak berfungsi di perangkat seluler.

Contoh-contoh diberikan dalam urutan kompleksitas (menurut pendapat subjektif saya), jadi hal yang paling menarik adalah pada akhirnya.

Koch kepingan salju

axiom = "F--F--F"
rules = {"F":"F+F--F+F"}
iterations = 4 # TOP: 7
angle = 60


Pulau Koch Square

axiom = "F+F+F+F"
rules = {"F":"F-F+F+FFF-F-F+F"}
iterations = 2 # TOP: 4
angle = 90


Kristal

axiom = "F+F+F+F"
rules = {"F":"FF+F++F+F"}
iterations = 3 # TOP: 6
angle = 90


Kepingan salju persegi

axiom = "F--F"
rules = {"F":"F-F+F+F-F"}
iterations = 4 # TOP: 6
angle = 90


Fraktal Wicheka

axiom = "F-F-F-F"
rules = {"F":"F-F+F+F-F"}
iterations = 4 # TOP: 6
angle = 90


Kurva Retribusi

axiom = "F"
rules = {"F":"+F--F+"}
iterations = 10 # TOP: 16
angle = 45


Karpet Sierpinski

axiom = "YF"
rules = {"X":"YF+XF+Y", "Y":"XF-YF-X"}
iterations = 1 # TOP: 10
angle = 60


Kisi Sierpinski

axiom = "FXF--FF--FF"
rules = {"F":"FF", "X":"--FXF++FXF++FXF--"}
iterations = 7 # TOP: 8
angle = 60


Kotak

axiom = "F+F+F+F"
rules = {"F":"FF+F+F+F+FF"}
iterations = 3 # TOP: 5
angle = 90


Ubin

axiom = "F+F+F+F"
rules = {"F":"FF+F-F+F+FF"}
iterations = 3 # TOP: 4
angle = 90


Dering

axiom = "F+F+F+F"
rules = {"F":"FF+F+F+F+F+F-F"}
iterations = 2 # TOP: 4
angle = 90


Salib 2

axiom = "F+F+F+F"
rules = {"F":"F+F-F+F+F"}
iterations = 3 # TOP: 6
angle = 90


Pentapleksitas

axiom = "F++F++F++F++F"
rules = {"F":"F++F++F+++++F-F++F"}
iterations = 1 # TOP: 5
angle = 36


32 segmen kurva

axiom = "F+F+F+F"
rules = {"F":"-F+F-F-F+F+FF-F+F+FF+F-F-FF+FF-FF+F+F-FF-F-F+FF-F-F+F+F-F+"}
iterations = 3 # TOP: 3
angle = 90


Kurva Peano Gosper

axiom = "FX"
rules = {"X":"X+YF++YF-FX--FXFX-YF+", "Y":"-FX+YFYF++YF+FX--FX-Y"}
iterations = 4 # TOP: 6
angle = 60


Kurva Sierpinski

axiom = "F+XF+F+XF"
rules = {"X":"XF-F+F-XF+F+XF-F+F-X"}
iterations = 4 # TOP: 8
angle = 90


Lembar Pertanyaan Krishna

axiom = " -X--X"
rules = {"X":"XFX--XFX"}
iterations = 3 # TOP: 9
angle = 45


Fraktal Gosper Square

axiom = "YF"
rules = {"X": "XFX-YF-YF+FX+FX-YF-YFFX+YF+FXFXYF-FX+YF+FXFX+YF-FXYF-YF-FX+FX+YFYF-", 
        "Y": "+FXFX-YF-YF+FX+FXYF+FX-YFYF-FX-YF+FXYFYF-FX-YFFX+FX+YF-YF-FX+FX+YFY"}
iterations = 2 # TOP: 3
angle = 90


Kurva Moore

axiom = "LFL-F-LFL"
rules = {"L":"+RF-LFL-FR+", "R":"-LF+RFR+FL-"}
iterations = 0 # TOP: 8
angle = 90


Kurva Hilbert

axiom = "L"
rules = {"L":"+RF-LFL-FR+", "R":"-LF+RFR+FL-"}
iterations = 8 # TOP: 9
angle = 90


Hilbert Curve II

axiom = "X"
rules = {"X":"XFYFX+F+YFXFY-F-XFYFX", "Y":"YFXFY-F-XFYFX+F+YFXFY"}
iterations = 4 # TOP: 6
angle = 90


Kurva Peano

axiom = "F"
rules = {"F":"F+F-F-F-F+F+F+F-F"}
iterations = 2 # TOP: 5
angle = 90


Menyeberang

axiom = "F+F+F+F"
rules = {"F":"F+FF++F+F"}
iterations = 3 # TOP: 6
angle = 90


Segi tiga

axiom = "F+F+F"
rules = {"F":"F-F+F"}
iterations = 2 # TOP: 9
angle = 120


Kurva naga

axiom = "FX"
rules = {"X":"X+YF+", "Y":"-FX-Y"}
iterations = 8 # TOP: 16
angle = 90


Kurva Terdragon

axiom = "F"
rules = {"F":"F-F+F"}
iterations = 5 # TOP: 10
angle = 120


Kurva Naga Ganda

axiom = "FX+FX"
rules = {"X":"X+YF+", "Y":"-FX-Y"}
iterations = 6 # TOP: 16
angle = 90


Kurva Triple Dragon

axiom = "FX+FX+FX"
rules = {"X":"X+YF+", "Y":"-FX-Y"}
iterations = 7 # TOP: 15
angle = 90


Kode

Semua contoh di atas diperoleh dengan menggunakan kode yang sama, dan ketika mengerjakannya beberapa kesulitan muncul (misalnya, bagaimana menjaga fraktal di tengah sejauh mungkin), bekerja dengan warna, inversi, offset, serta menyediakan ekspor cepat ke format vektor. Di sini saya hanya menunjukkan kepada Anda versi yang paling sederhana.
Versi ini menampilkan fraktal dalam warna hitam dan putih dan tidak dilengkapi dengan fungsi ekspor

import turtle

def create_l_system(iters, axiom, rules):
    start_string = axiom
    if iters == 0:
        return axiom
    end_string = ""
    for _ in range(iters):
        end_string = "".join(rules[i] if i in rules else i for i in start_string)
        start_string = end_string

    return end_string


def draw_l_system(t, instructions, angle, distance):
    for cmd in instructions:
        if cmd == 'F':
            t.forward(distance)
        elif cmd == '+':
            t.right(angle)
        elif cmd == '-':
            t.left(angle)


def main(iterations, axiom, rules, angle, length=8, size=2, y_offset=0,
        x_offset=0, offset_angle=0, width=450, height=450):

    inst = create_l_system(iterations, axiom, rules)

    t = turtle.Turtle()
    wn = turtle.Screen()
    wn.setup(width, height)

    t.up()
    t.backward(-x_offset)
    t.left(90)
    t.backward(-y_offset)
    t.left(offset_angle)
    t.down()
    t.speed(0)
    t.pensize(size)
    draw_l_system(t, inst, angle, length)
    t.hideturtle()

    wn.exitonclick()


Penjelasan Kode

import turtle


Pertama, Anda perlu mengimpor modul Turtle

def create_l_system(iters, axiom, rules):
    start_string = axiom
    if iters == 0:
        return axiom
    end_string = ""
    for _ in range(iters):
        end_string = "".join(rules[i] if i in rules else i for i in start_string)
        start_string = end_string

    return end_string

Maka Anda perlu membuat sistem-L, yang akan menjadi seperangkat instruksi untuk kura-kura. Kami mendefinisikan fungsi create_l_systemyang menerima jumlah iterasi, aksioma, dan aturan konstruksi. Dimulai dengan aksioma dan menggunakan variabel bantu end_string, jika iterasi adalah 0, maka akan mengembalikan aksioma, karena beberapa fraktal dapat diterapkan dengan nol iterasi. Dalam hal ini, diasumsikan bahwa aturan memiliki bentuk kamus, sehingga setiap kunci unik, mewakili simbol, dan nilainya menunjukkan apa dan apa yang perlu diganti. Jadi kami menggabungkan semua penggantian untuk setiap karakter dan akhirnya mendapatkan string untuk iterasi berikutnya.

def draw_l_system(t, instructions, angle, distance):
    for cmd in instructions:
        if cmd == 'F':
            t.forward(distance)
        elif cmd == '+':
            t.right(angle)
        elif cmd == '-':
            t.left(angle)

Kemudian kami menentukan draw_l_systemyang menerima kura-kura, satu set instruksi (output dari sistem-L), sudut untuk belok kiri atau kanan, dan panjang setiap garis individu. Ini terdiri dari struktur sederhana elifuntuk masing-masing tim yang ditetapkan sebelumnya.

def main(iterations, axiom, rules, angle, length=8, size=2, y_offset=0,
        x_offset=0, offset_angle=0, width=450, height=450):

    inst = create_l_system(iterations, axiom, rules)

    t = turtle.Turtle()
    wn = turtle.Screen()
    wn.setup(width, height)

    t.up()
    t.backward(-x_offset)
    t.left(90)
    t.backward(-y_offset)
    t.left(offset_angle)
    t.down()
    t.speed(0)
    t.pensize(size)
    draw_l_system(t, inst, angle, length)
    t.hideturtle()

    wn.exitonclick()

Akhirnya, mari kita bicara tentang fungsi main, yang mengambil semua parameter yang diperlukan untuk generasi L-sistem, serta y_offset, x_offset, offset_angle, widthdan height. Tiga yang pertama menggambarkan perpindahan kura-kura, perlu hanya menempatkan grafik pada kanvas seperti yang kita inginkan.

Fungsi pertama menghasilkan serangkaian instruksi dan menyimpannya di inst, kemudian menginisialisasi kura-kura dan layar dan menempatkan kura-kura pada titik tertentu, kemudian menggambar grafik sesuai dengan instruksi dan menunggu klik untuk menutup.

Pertimbangan khusus

Seperti yang saya sebutkan di atas, banyak batasan yang tersisa di sini. Pertama, kami tidak memberi kura-kura kemampuan untuk bergerak tanpa rendering; ini akan membutuhkan karakter lain. Juga tidak ada simbol untuk mundur kembali, dan untuk mengingat posisi sebelumnya. Mereka tidak diperlukan untuk semua fraktal yang dibahas di atas, tetapi diperlukan untuk beberapa fraktal lainnya (misalnya, pohon fraktal).

Sumber daya tambahan

Internet memiliki banyak sumber daya tentang fraktal, di mana mereka dianggap baik dari sudut pandang pemrograman dan dari sudut pandang matematika. Dua berikut ini tampak sangat menarik bagi saya: 3Blue1Brown (matematika) dan CodingTrain (kode).

Artikel ini terinspirasi oleh posting dari Dunia Matematika dan artikel tersebut Paula Burka.

All Articles