浅析Mandelbrot集合及其图形的绘制



2008-10-10 00:31 
Anders Cui 
阅读(23297
评论(12
编辑 
收藏 
举报

1967年,美国数学家Mandelbrot曾出这样一个著名的问题:英格兰的海岸线到底有多长?这个问题在数学上可以理解为:用折线段拟合任意不规则的连续曲线是否一定有效?这个问题的提出实际上是对以欧氏几何为核心的传统几何的挑战,这个问题也是分形几何学的发端。而Mandelbrot集合则是分形几何的经典集合,它的图形表示可以让我们认识到纯粹的数学之美。由于分形几何学知识的匮乏,本文只能给出Mandelbrot集合的定义,并以最容易理解的方式绘制出该集合。这里使用的语言是F#,而不是C#,以后还会有更多采用F#的例子 🙂

引言

在《Foundations of F#》的第七章中,作者在介绍Math命名空间时举的例子是绘制Mandelbrot集合。这个看起来挺奇怪的东东以前还真没见过,网上一查才知道,原来它是如此的优美动人。由于该集合的定义与分形相关,所以先来了解下分形的概念。

什么是分形(Fractal)

1967年,美国数学家Mandelbrot曾出这样一个著名的问题:英格兰的海岸线到底有多长?这个问题在数学上可以理解为:用折线段拟合任意不规则的连续曲线是否一定有效?这个问题的提出实际上是对以欧氏几何为核心的传统几何的挑战。

1975年,Mandelbrot在其《自然界中的分形几何》一书中引入了分形(fractal)这一概念。从字面意义上讲, fractal是碎块、碎片的意思,然而这并不能概括Mandelbrot的分形概念,尽管目前还没有一个让各方都满意的分形定义,但在数学上大家都认为分形有以下几个特点:

1. 具有无限精细的结构;
2. 比例自相似性;
3. 一般它的分数维大子它的拓扑维数;
4. 可以由非常简单的方法定义,并由递归、迭代产生。

    据说,南非海岸线的维数是1.02,英国西岸的维数是1.25。

    下面的两幅图有助于我们理解它的概念:

    fractal1

    fractal2

    需要注意的是,分形往往由递归、迭代产生,但是我们在纸上做出的图只能作有限次的递归、迭代。

    分形几何学已在自然界与物理学中得到了应用。如在显微镜下观察落入溶液中的一粒花粉,会看见它不间断地作无规则运动(布朗运动),这是花粉在大量液体分子的无规则碰撞(每秒钟多达十亿亿次)下表现的平均行为。布朗粒子的轨迹,由各种尺寸的折线连成。只要有足够的分辨率,就可以发现原以为是直线段的部分,其实由大量更小尺度的折线连成。

    什么是Mandelbrot集合?

    Mandelbrot集合是在复平面上组成分形的点的集合,它正是以数学家Mandelbrot命名。

    Mandelbrot集合可以用复二次多项式

    f_ c(z) =z^{2}+ c \, 来定义

    其中c是一个复参数。对于每一个c,从z = 0\,开始对fc(z)进行迭代。

    序列 (0, f_ c(0), f_c(f_ c(0)), f_ c(f_ c(f_ c(0))), \ldots) 的元素的模(复数具有模的概念)或者延伸到无穷大,或者只停留在有限半径的圆盘内。Mandelbrot集合就是使以上序列不延伸至无限大的所有c点的集合。

    从数学上来讲,Mandelbrot集合是一个复数的集合。一个给定的复数c或者属于Mandelbrot集合M,或者不属于。比如,取c = 1,那么这个序列就是(0, 1, 2, 5, 26, …),显然它的值会趋于无穷大;而如果取c = i,那么序列就是(0, i, -1+i, -i, -1+i, -i,…),它的值会一直停留在有限半径的圆盘内。

    事实上,一个点属于Mandelbrot集合当且仅当它对应的序列(由上面的二项式定义)中的任何元素的模都不大于2。这里的2就是上面提到的“有限半径”。

    在计算机上绘制Mandelbrot集合

    计算机的屏幕上的像素只有有限个,而Mandelbrot集合中的点则有无限个。

    Mandelset_hires

    观察上面复平面的局部,Mandelbrot集合即黑色区域,实部从-2到1,虚部从-1到1,那么将两个点(-2, 1)和(1, -1)作为一个矩形的左上角顶点和右下角顶点,那么这个矩形就包含了整个Mandelbrot集合,该矩形的长为3,宽为2。我们可以将这个矩形与屏幕上的区域进行映射,也就是将屏幕上的一个像素映射为该矩形内的一点,如果该点属于Mandelbrot集合,就将该像素着为黑色,这样逐一对每个像素进行判断和着色,就可以模拟绘制Mandelbrot集合了。该矩形的长宽比为3:2,我们在屏幕上可以取600 * 400的矩形区域。

    完成映射后来考虑如何判断一个点是否属于该集合。其根据就是上面的结论“一个点属于Mandelbrot集合当且仅当它对应的序列(由上面的二项式定义)中的任何元素的模都不大于2”,由于序列的的元素有无穷多个,我们只能取有限的迭代次数来模拟了,比如取100或1000次。

    我们用Microsoft.FSharp.Math.Notation.complex类型来表示一个复数,它的Magnitude属性表示复数的模,我们可以通过一定次数(比如100次)的迭代,来看看前100项是不是都满足条件,如果满足就认为这个复数在Mandelbrot集合内。下面是完整的程序。

    F# Code - 绘制Mandelbrot集合
    #light
    open System
    open System.Drawing
    open System.Windows.Forms
    open Microsoft.FSharp.Math
    open Microsoft.FSharp.Math.Notation

    // 迭代次数
    let maxIterations = 100

    // 映射比例
    let scalingFactor = 1.0 / 200.0
    // 将像素映射为复数
    let mapPlane(x, y) =
    let fx = ((float x) * scalingFactor) - 2.0
    let fy = ((float y) * scalingFactor) - 1.0
    complex fx fy

    let mutable iteration = 0
    let mutable current = complex 0.0 0.0
    let mutable temp = complex 0.0 0.0

    let form =
    let image = new Bitmap(600, 400)
    for x = 0 to image.Width - 1 do
    for y = 0 to image.Height - 1 do
    iteration
    <- 0
    current
    <- mapPlane(x, y)
    temp
    <- current
    // 判断当前点是否在Mandelbrot集合内
    while(temp.Magnitude <= 2.0 && iteration < maxIterations) do
    temp
    <- temp * temp + current
    iteration
    <- iteration + 1

    // 如果在,像素为黑色
    if iteration = maxIterations then
    image.SetPixel(x, y, Color.Black)
    else
    image.SetPixel(x, y, Color.White)

    let temp = new Form() in
    temp.Paint.Add(
    fun e -> e.Graphics.DrawImage(image, 0, 0))
    temp.Height
    <- 435
    temp.Width
    <- 600
    temp.Text
    <- "Draw Mandelbrot Set"
    temp

    [<STAThread
    >]
    do Application.Run(form)

    下面是效果图

    这张图是黑白的,我们可以把它变成彩色的。看这一部分代码:

    F# Code
    // 如果在,像素为黑色
    if iteration = maxIterations then
    image.SetPixel(x, y, Color.Black)
    else
    image.SetPixel(x, y, Color.White)

    只有iteration等于maxIterations,当前的复数才属于Mandelbrot集合,这时将像素着为黑色;如果不在集合内,我们可以想办法着为彩色。考虑红橙黄绿蓝靛紫七种颜色,把它们存储在数组中,然后根据iteration的值来取相应的颜色:

    Code
    // 七种颜色
    let colors = [| Color.Red; Color.Orange; Color.Yellow;
    Color.Green; Color.Blue; Color.Indigo;
    Color.Purple;
    |]

    // 如果在,像素为黑色
    if iteration = maxIterations then
    image.SetPixel(x, y, Color.Black)
    else
    image.SetPixel(x, y, colors.[iteration % colors.Length])

    完整的代码是:

    F# Code - 彩色的Mandelbrot
    #light
    open System
    open System.Drawing
    open System.Windows.Forms
    open Microsoft.FSharp.Math
    open Microsoft.FSharp.Math.Notation

    // 迭代次数
    let maxIterations = 30

    // 七种颜色
    let colors = [| Color.Red; Color.Orange; Color.Yellow;
    Color.Green; Color.Blue; Color.Indigo;
    Color.Purple;
    |]

    // 映射比例
    let scalingFactor = 1.0 / 200.0
    // 将像素映射为坐标
    let mapPlane(x, y) =
    let fx = ((float x) * scalingFactor) - 2.0
    let fy = ((float y) * scalingFactor) - 1.0
    complex fx fy

    let mutable iteration = 0
    let mutable current = complex 0.0 0.0
    let mutable temp = complex 0.0 0.0

    let form =
    let image = new Bitmap(600, 400)
    for x = 0 to image.Width - 1 do
    for y = 0 to image.Height - 1 do
    iteration
    <- 0
    current
    <- mapPlane(x, y)
    temp
    <- current
    // 判断当前点是否在Mandelbrot集合内
    while(temp.Magnitude <= 2.0 && iteration < maxIterations) do
    temp
    <- temp * temp + current
    iteration
    <- iteration + 1

    // 如果在,像素为黑色
    if iteration = maxIterations then
    image.SetPixel(x, y, Color.Black)
    else
    image.SetPixel(x, y, colors.[iteration % colors.Length])

    let temp = new Form() in
    temp.Paint.Add(
    fun e -> e.Graphics.DrawImage(image, 0, 0))
    temp.Height
    <- 435
    temp.Width
    <- 600
    temp.Text
    <- "Drawing Mandelbrot Set"
    temp

    [<STAThread
    >]
    do Application.Run(form)

    下面是效果图

    当然这只是着彩色方式的一种,如果你有兴趣,可以查看后面给出的参考文章。

    小结

    Mandelbrot集合的图形表示可以让我们认识到纯粹的数学之美,与之相关的分形几何学则是无处不在的,不得不感叹数学的力量。由于分形几何学知识的匮乏,本文只能给出Mandelbrot集合的定义,并以最容易理解的方式绘制出该集合。这里使用的语言是F#,而不是C#,以后会尽量作出一些采用F#的更为实用的例子。

    参考:

    《Foundations of F#》 by Robert Pickering
    神奇的分形艺术
    Mandelbrot_Set_Wikipedia
    分形是什么?

    版权声明:本文为anderslly原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://www.cnblogs.com/anderslly/archive/2008/10/10/mandelbrot-set-by-fsharp.html