== Chapter 5: Programming Fractals

=== Introduction

Fractals are complex patterns that are self-similar across different scales. They are fascinating both in their mathematical properties and their visual appeal. In this chapter, we will explore how to program fractals using Elixir and Go, focusing on some of the most famous fractal patterns such as the Mandelbrot set and the Sierpinski triangle.

=== The Mandelbrot Set

The Mandelbrot set is a set of complex numbers that produces a distinctive and famous fractal shape. The set is defined by iterating the function:

[stem]
++++
z_{n+1} = z_n^2 + c
++++

==== Plotting the Mandelbrot Set in Elixir

Let's start with a basic Elixir program to plot the Mandelbrot set.

[source,elixir]
----
defmodule Mandelbrot do
  def mandelbrot(c, max_iter) do
    iterate(c, 0, 0, max_iter)
  end

  defp iterate(_c, _z, n, max_iter) when n >= max_iter, do: n
  defp iterate(c, z, n, max_iter) when abs(z) > 2, do: n
  defp iterate(c, z, n, max_iter) do
    iterate(c, z*z + c, n + 1, max_iter)
  end

  def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter) do
    for x <- 0..(width-1), y <- 0..(height-1) do
      r = xmin + (xmax - xmin) * x / width
      i = ymin + (ymax - ymin) * y / height
      c = Complex.new(r, i)
      {x, y, mandelbrot(c, max_iter)}
    end
  end
end

plot = Mandelbrot.mandelbrot_set(-2.0, 1.0, -1.5, 1.5, 800, 800, 256)
:Gnuplot.plot(plot)
----

==== Plotting the Mandelbrot Set in Go

Here's a Go program to plot the Mandelbrot set.

[source,go]
----
package main

import (
	"image"
	"image/color"
	"image/png"
	"math/cmplx"
	"os"
)

func mandelbrot(c complex128, maxIter int) int {
	z := complex(0, 0)
	for n := 0; n < maxIter; n++ {
		z = z*z + c
		if cmplx.Abs(z) > 2 {
			return n
		}
	}
	return maxIter
}

func mandelbrotSet(xmin, xmax, ymin, ymax float64, width, height, maxIter int) *image.Gray {
	img := image.NewGray(image.Rect(0, 0, width, height))
	for py := 0; py < height; py++ {
		for px := 0; px < width; px++ {
			x := float64(px)/float64(width)*(xmax-xmin) + xmin
			y := float64(py)/float64(height)*(ymax-ymin) + ymin
			c := complex(x, y)
			m := mandelbrot(c, maxIter)
			img.SetGray(px, py, color.Gray{255 - uint8(m)})
		}
	}
	return img
}

func main() {
	xmin, xmax, ymin, ymax := -2.0, 1.0, -1.5, 1.5
	width, height := 800, 800
	maxIter := 256

	img := mandelbrotSet(xmin, xmax, ymin, ymax, width, height, maxIter)

	file, _ := os.Create("mandelbrot.png")
	defer file.Close()
	png.Encode(file, img)
}
----

=== The Sierpinski Triangle

The Sierpinski triangle is a fractal that is formed by recursively subdividing an equilateral triangle into smaller equilateral triangles.

==== Plotting the Sierpinski Triangle in Elixir

Here is an Elixir program to plot the Sierpinski triangle using recursion.

[source,elixir]
----
defmodule Sierpinski do
  def draw_triangle(x, y, size, depth, canvas) when depth == 0 do
    triangle = [{x, y}, {x + size / 2, y + size * :math.sqrt(3) / 2}, {x + size, y}]
    :egd.filled_polygon(canvas, triangle, :egd.color(:black))
  end

  def draw_triangle(x, y, size, depth, canvas) do
    draw_triangle(x, y, size / 2, depth - 1, canvas)
    draw_triangle(x + size / 2, y, size / 2, depth - 1, canvas)
    draw_triangle(x + size / 4, y + size * :math.sqrt(3) / 4, size / 2, depth - 1, canvas)
  end
end

{:ok, canvas} = :egd.create(800, 800)
Sierpinski.draw_triangle(0, 0, 800, 5, canvas)
:image.create(:png, canvas)
----

==== Plotting the Sierpinski Triangle in Go

Here is a Go program to plot the Sierpinski triangle using recursion.

[source,go]
----
package main

import (
	"image"
	"image/color"
	"image/png"
	"os"
)

func drawTriangle(img *image.Gray, x, y, size, depth int) {
	if depth == 0 {
		drawFilledPolygon(img, [][]int{{x, y}, {x + size / 2, y + int(float64(size) * 0.866)}, {x + size, y}}, 0)
	} else {
		drawTriangle(img, x, y, size / 2, depth - 1)
		drawTriangle(img, x + size / 2, y, size / 2, depth - 1)
		drawTriangle(img, x + size / 4, y + int(float64(size) * 0.866 / 2), size / 2, depth - 1)
	}
}

func drawFilledPolygon(img *image.Gray, points [][]int, value uint8) {
	for i := 0; i < len(points); i++ {
		x0, y0 := points[i][0], points[i][1]
		x1, y1 := points[(i + 1) % len(points)][0], points[(i + 1) % len(points)][1]
		drawLine(img, x0, y0, x1, y1, value)
	}
}

func drawLine(img *image.Gray, x0, y0, x1, y1 int, value uint8) {
	dx := x1 - x0
	dy := y1 - y0
	steps := max(abs(dx), abs(dy))

	if steps == 0 {
		img.SetGray(x0, y0, color.Gray{value})
		return
	}

	for i := 0; i <= steps; i++ {
		x := x0 + i * dx / steps
		y := y0 + i * dy / steps
		img.SetGray(x, y, color.Gray{value})
	}
}

func main() {
	width, height := 800, 800
	img := image.NewGray(image.Rect(0, 0, width, height))
	drawTriangle(img, 0, 0, width, 5)

	file, _ := os.Create("sierpinski.png")
	defer file.Close()
	png.Encode(file, img)
}
----

=== Conclusion

Fractals are an excellent way to understand the beauty and complexity of mathematical patterns. By programming these patterns, we not only appreciate their aesthetic appeal but also gain insights into their mathematical properties.

=== Further Reading

For more information on fractals and programming, check out the following resources:

* https://en.wikipedia.org/wiki/Mandelbrot_set[Mandelbrot Set - Wikipedia]
* https://en.wikipedia.org/wiki/Sierpinski_triangle[Sierpinski Triangle - Wikipedia]

=== References

1. Mandelbrot, B. B. (1982). _The Fractal Geometry of Nature_. New York: W.H. Freeman and Company.
2. Peitgen, H.-O., Jürgens, H., & Saupe, D. (1992). _Chaos and Fractals: New Frontiers of Science_. New York: Springer.

=== Appendix

==== Image and Code Credits

* Mandelbrot Set: Code adapted from various fractal tutorials in Elixir and Go.
* Sierpinski Triangle: Code adapted from various fractal tutorials in Elixir and Go.
