Материал: Анализ эффективности функционального программирования на языке F# для многоядерных процессоров

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

ЛИТЕРАТУРА

1.      <http://www.ict.edu.ru/ft/005135//ch3.pdf>

.        <http://ru.wikipedia.org/wiki/Язык_функционального_программирования>

.        <http://ru.wikipedia.org/wiki/Препроцессор>

.        <http://ru.wikipedia.org/wiki/Lisp>

.        <http://progopedia.ru/language/ml/>

.        <http://oops.math.spbu.ru/~msk/languages.functional.html>

.        <http://en.wikipedia.org/wiki/Hope_(programming_language)>

.        <http://progopedia.ru/language/miranda/>

.        <http://ru.wikipedia.org/wiki/Haskell>

.        <http://www.intuit.ru/department/pl/haskel98/1/>

.        <http://ru.wikipedia.org/wiki/Охрана_(программирование)>

.        <http://www.uchi-it.ru/7/2/3.html>

.        <http://www.rsdn.ru/article/funcprog/fp.xml>

.        <http://ru.wikipedia.org/wiki/Функциональное_программирование>

.        <http://msdn.microsoft.com/ru-ru/library/bb669144.aspx>

.        <http://habrahabr.ru/blogs/net/71656/>

.        <http://fprog.ru/2010/issue5/maxim-moiseev-et-al-fsharp-intro/>

.        <http://www.realcoding.net/article/view/2764>

.        <http://www.dartmouth.edu/~rc/classes/intro_mpi/parallel_prog_compare.html>

.        <http://msdn.microsoft.com/en-us/library/dd460693.aspx>

.        <http://ru.wikipedia.org/wiki/Алгоритм_Штрассена>

.        <http://blogs.msdn.com/b/pfxteam/archive/2009/12/09/9934811.aspx>

.        <http://ru.wikipedia.org/wiki/Множество_Мандельброта>

.        <http://ru.wikipedia.org/wiki/Фрактал>

.        <http://www.chaostarantula.narod.ru/ToC/1.htm>

.        <http://drdobbs.com/embedded-systems/196902836>

27.    Tomas Petricek,Jon Skeet Functional Programming for the Real World/Manning/2009

28.    Сошников Д.В. - лекции (“Функциональное программирование”)/2008/Lect1, видео (“F# : Новый язык программирования .NET”)/Платформа/ 2009

.        Тим Мэттсон, Андрей Чернышев Введение в технологии параллельного программирования /Intel® Software Network/2009

30.    Don Syme, Adam Granicz, and Antonio Cisternino Expert F#/Apress/2010

ПРИЛОЖЕНИЕ 1

Тексты программ на F#

А. Программа для умножения матриц

#light//включение light-синтаксисаSystemSystem.Threading

/// Измерение времени выполнения функции

let Time f =timer = System.Diagnostics.Stopwatch.StartNew ()y = f ()"Time taken = %O" timer.ElapsedMatrixMultiplyDemo () =

/// Обыкновенное умножениеMultiply (A: float[,]) (B: float[,])(C: float[,]) =n = Array2D.length1 Ai = 0 to (n-1) doj=0 to n-1 dok=0 to n-1 do.[i,j] <- C.[i,j] + A.[i,k] * B.[k,j]

/// Простое умножениеMultiplyX (A: matrix) (B: matrix) =

(fun x y -> x * y) A B //анонимная функция

/// Быстрое умножение с использованием алгоритма Parallel-FX

let PFXMultiply (A: float[,]) (B: float[,]) (C: float[,]) =n = Array2D.length1 ARowTask i =j=0 to n-1 dok=0 to n-1 do.[i,j] <- C.[i,j] + A.[i,k] * B.[k,j]

//далее идет инструкия из Parallel Extensions .NET.For(0, (n-1), new Action<int>(RowTask))

///Создание Z-матрицCreateZMatrix (A: float[,]) (B: float[,]) (C: float[,] ) =n = Array2D.length1 AzMaskSize = int(Math.Log(float(n*n),float(2)))DecalcZ z =mutable z1 = zmutable i = 0mutable j = 0mutable bit = 1(bit <= z1) do<- j ||| (z1 &&& bit)<- z1 >>> 1<- i||| (z1 &&& bit)<- bit <<< 1

(i,j) //возвращается tuplef i (M: float[,]) =(i1,j1)=DecalcZ i.[i1,j1]zA=Array.init (1<<<zMaskSize) (fun i -> f i A)zB=Array.init (1<<<zMaskSize) (fun i -> f i B)mutable zC=Array.init (1<<<zMaskSize) (fun i -> f i C)

(zA,zB,zC)  //массив zC теперь изменяемый

///параллельное Z-умножениеPZMatrixMultiply (zA:float[]) (zB:float[]) (zC:float[]) =

let n=Array.length zAZCode = 0MaskBits = int(Math.Log(float(n),float(2)))rec zMultiply (aZCode,aMaskBits) (bZCode,bMaskBits) (cZCode,cMaskBits)=aMaskBits >=2 thenGetSubcells (zCode, maskBits) = //разбиение на 4 ячейкиsubMaskBits = maskBits - 2zI =

[|

(zCode , subMaskBits)

(zCode ||| (1<<<subMaskBits), subMaskBits)

(zCode ||| (2<<<subMaskBits), subMaskBits)

(zCode ||| (3<<<subMaskBits), subMaskBits)

|]c1sub = GetSubcells (aZCode,aMaskBits)c2sub = GetSubcells (bZCode,aMaskBits)cRsub = GetSubcells (cZCode,aMaskBits)c1sub.[0] c2sub.[0] cRsub.[0]c1sub.[1] c2sub.[2] cRsub.[0]c1sub.[0] c2sub.[1] cRsub.[1]c1sub.[1] c2sub.[3] cRsub.[1]c1sub.[2] c2sub.[0] cRsub.[2]c1sub.[3] c2sub.[2] cRsub.[2]c1sub.[2] c2sub.[1] cRsub.[3]c1sub.[3] c2sub.[3] cRsub.[3].[cZCode] <- zA.[aZCode] * zB.[bZCode] + zC.[cZCode]PzMultiply (aZCode,aMaskBits) (bZCode,bMaskBits) (cZCode,cMaskBits)=aMaskBits >=2 thenGetSubcells (zCode, maskBits) =subMaskBits = maskBits - 2zI =

[|

(zCode , subMaskBits)

(zCode ||| (1<<<subMaskBits), subMaskBits)

(zCode ||| (2<<<subMaskBits), subMaskBits)

(zCode ||| (3<<<subMaskBits), subMaskBits)

|]c1sub = GetSubcells (aZCode,aMaskBits)c2sub = GetSubcells (bZCode,aMaskBits)cRsub = GetSubcells (cZCode,aMaskBits)

let tasks = [//разбиение на асинхронные потоки

async

{c1sub.[0] c2sub.[0] cRsub.[0]c1sub.[1] c2sub.[2] cRsub.[0]

}

{c1sub.[0] c2sub.[1] cRsub.[1]c1sub.[1] c2sub.[3] cRsub.[1]

}

{c1sub.[2] c2sub.[0] cRsub.[2]c1sub.[3] c2sub.[2] cRsub.[2]

}

{c1sub.[2] c2sub.[1] cRsub.[3]c1sub.[3] c2sub.[3] cRsub.[3]

}

]|> Async.Parallel |> Async.RunSynchronously |>ignore.[cZCode] <- zA.[aZCode] * zB.[bZCode] + zC.[cZCode]

//вычисление на последнем уровне(ZCode,MaskBits)(ZCode,MaskBits)(ZCode,MaskBits)

///простое Z-умножениеZMatrixMultiply (zA:float[]) (zB:float[]) (zC:float[]) =n=Array.length zAZCode = 0MaskBits = int(Math.Log(float(n),float(2)))rec zMultiply (aZCode,aMaskBits) (bZCode,bMaskBits) (cZCode,cMaskBits)=aMaskBits >=2 thenGetSubcells (zCode, maskBits) =subMaskBits = maskBits - 2zI =

[|

(zCode , subMaskBits)

(zCode ||| (1<<<subMaskBits), subMaskBits)

(zCode ||| (2<<<subMaskBits), subMaskBits)

(zCode ||| (3<<<subMaskBits), subMaskBits)

|]c1sub = GetSubcells (aZCode,aMaskBits)c2sub = GetSubcells (bZCode,bMaskBits)cRsub = GetSubcells (cZCode,cMaskBits)c1sub.[0] c2sub.[0] cRsub.[0]c1sub.[1] c2sub.[2] cRsub.[0]c1sub.[0] c2sub.[1] cRsub.[1]c1sub.[1] c2sub.[3] cRsub.[1]c1sub.[2] c2sub.[0] cRsub.[2]c1sub.[3] c2sub.[2] cRsub.[2]c1sub.[2] c2sub.[1] cRsub.[3]c1sub.[3] c2sub.[3] cRsub.[3].[cZCode] <- zA.[aZCode] * zB.[bZCode] + zC.[cZCode](ZCode,MaskBits)(ZCode,MaskBits)(ZCode,MaskBits)

zC

///Умножение с использование метода Штрассена

let StrassenMultiply (zA:float[]) (zB:float[]) (zC:float[]) =n=Array.length zAZCode = 0MaskBits = int(Math.Log(float(n),float(2)))rec Strassen (aZCode,aMaskBits) (bZCode,bMaskBits) (cZCode,cMaskBits)=GetSubcells (zCode, maskBits) =subMaskBits = maskBits - 2zI =

[|

(zCode , subMaskBits)

(zCode ||| (1<<<subMaskBits), subMaskBits)

(zCode ||| (2<<<subMaskBits), subMaskBits)

(zCode ||| (3<<<subMaskBits), subMaskBits)

|]aMaskBits >= 3 thenc1sub = GetSubcells (aZCode,aMaskBits)c2sub = GetSubcells (bZCode,aMaskBits)cRsub = GetSubcells (cZCode,aMaskBits)c1sub.[0] c2sub.[0] cRsub.[0]c1sub.[1] c2sub.[2] cRsub.[0]c1sub.[0] c2sub.[1] cRsub.[1]c1sub.[1] c2sub.[3] cRsub.[1]c1sub.[2] c2sub.[0] cRsub.[2]c1sub.[3] c2sub.[2] cRsub.[2]c1sub.[2] c2sub.[1] cRsub.[3]c1sub.[3] c2sub.[3] cRsub.[3]a0code=aZCodea1code=aZCode ||| 1a2code=aZCode ||| 2a3code=aZCode ||| 3b0code=bZCodeb1code=bZCode ||| 1b2code=bZCode ||| 2b3code=bZCode ||| 3c0code=cZCodec1code=cZCode ||| 1c2code=cZCode ||| 2c3code=cZCode ||| 3p1=(zA.[a0code]+zA.[a3code])*(zB.[b0code]+ zB.[b3code]);p2=(zA.[a2code]+zA.[a3code])* zB.[b0code];p3=zA.[a0code] *(zB.[b1code]- zB.[b3code]);p4=zA.[a3code] *(zB.[b2code]- zB.[b0code]);p5=(zA.[a0code]+zA.[a1code])* zB.[b3code];p6=(zA.[a2code]-zA.[a0code])*(zB.[b0code]+ zB.[b1code]);p7=(zA.[a1code]-zA.[a3code])*(zB.[b2code]+ zB.[b3code]);.[c0code] <- p1+p4-p5+p7+zC.[c0code];.[c1code] <- p3+p5+zC.[c1code];.[c2code] <- p2+p4+zC.[c2code];.[c3code] <- p1-p2+p3+p6+zC.[c3code];(ZCode,MaskBits)(ZCode,MaskBits)(ZCode,MaskBits)

zC

///Параллельная версия умножения с использованием метода штрассена

let ParStrassenMultiply (zA:float[]) (zB:float[]) (zC:float[]) =n=Array.length zAZCode = 0MaskBits = int(Math.Log(float(n),float(2)))rec Strassen (aZCode,aMaskBits) (bZCode,bMaskBits) (cZCode,cMaskBits)=GetSubcells (zCode, maskBits) =subMaskBits = maskBits - 2zI =

[|

(zCode , subMaskBits)

(zCode ||| (1<<<subMaskBits), subMaskBits)

(zCode ||| (2<<<subMaskBits), subMaskBits)

(zCode ||| (3<<<subMaskBits), subMaskBits)

|]aMaskBits >= 3 thenc1sub = GetSubcells (aZCode,aMaskBits)c2sub = GetSubcells (bZCode,aMaskBits)cRsub = GetSubcells (cZCode,aMaskBits)c1sub.[0] c2sub.[0] cRsub.[0]c1sub.[1] c2sub.[2] cRsub.[0]c1sub.[0] c2sub.[1] cRsub.[1]c1sub.[1] c2sub.[3] cRsub.[1]c1sub.[2] c2sub.[0] cRsub.[2]c1sub.[3] c2sub.[2] cRsub.[2]c1sub.[2] c2sub.[1] cRsub.[3]c1sub.[3] c2sub.[3] cRsub.[3]a0code=aZCodea1code=aZCode ||| 1a2code=aZCode ||| 2a3code=aZCode ||| 3b0code=bZCodeb1code=bZCode ||| 1b2code=bZCode ||| 2b3code=bZCode ||| 3c0code=cZCodec1code=cZCode ||| 1c2code=cZCode ||| 2c3code=cZCode ||| 3p1=(zA.[a0code]+zA.[a3code])*(zB.[b0code]+ zB.[b3code]);p2=(zA.[a2code]+zA.[a3code])* zB.[b0code];p3=zA.[a0code] *(zB.[b1code]- zB.[b3code]);p4=zA.[a3code] *(zB.[b2code]- zB.[b0code]);p5=(zA.[a0code]+zA.[a1code])* zB.[b3code];p6=(zA.[a2code]-zA.[a0code])*(zB.[b0code]+ zB.[b1code]);p7=(zA.[a1code]-zA.[a3code])*(zB.[b2code]+ zB.[b3code]);.[c0code] <- p1+p4-p5+p7+zC.[c0code];.[c1code] <- p3+p5+zC.[c1code];.[c2code] <- p2+p4+zC.[c2code];.[c3code] <- p1-p2+p3+p6+zC.[c3code];rec ParStrassen (aZCode,aMaskBits) (bZCode,bMaskBits) (cZCode,cMaskBits)=GetSubcells (zCode, maskBits) =subMaskBits = maskBits - 2zI =

[|

(zCode , subMaskBits)

(zCode ||| (1<<<subMaskBits), subMaskBits)

(zCode ||| (2<<<subMaskBits), subMaskBits)

(zCode ||| (3<<<subMaskBits), subMaskBits)

|]aMaskBits >= 3 thenc1sub = GetSubcells (aZCode,aMaskBits)c2sub = GetSubcells (bZCode,aMaskBits)cRsub = GetSubcells (cZCode,aMaskBits)tasks = [

{c1sub.[0] c2sub.[0] cRsub.[0]c1sub.[1] c2sub.[2] cRsub.[0]

}

{c1sub.[0] c2sub.[1] cRsub.[1]c1sub.[1] c2sub.[3] cRsub.[1]

}

{c1sub.[2] c2sub.[0] cRsub.[2]c1sub.[3] c2sub.[2] cRsub.[2]

}

{c1sub.[2] c2sub.[1] cRsub.[3]c1sub.[3] c2sub.[3] cRsub.[3]

}

]|> Async.Parallel |> Async.RunSynchronously |>ignorea0code=aZCodea1code=aZCode ||| 1a2code=aZCode ||| 2a3code=aZCode ||| 3b0code=bZCodeb1code=bZCode ||| 1b2code=bZCode ||| 2b3code=bZCode ||| 3c0code=cZCodec1code=cZCode ||| 1c2code=cZCode ||| 2c3code=cZCode ||| 3p1=(zA.[a0code]+zA.[a3code])*(zB.[b0code]+ zB.[b3code]);p2=(zA.[a2code]+zA.[a3code])* zB.[b0code];p3=zA.[a0code] *(zB.[b1code]- zB.[b3code]);p4=zA.[a3code] *(zB.[b2code]- zB.[b0code]);p5=(zA.[a0code]+zA.[a1code])* zB.[b3code];p6=(zA.[a2code]-zA.[a0code])*(zB.[b0code]+ zB.[b1code]);p7=(zA.[a1code]-zA.[a3code])*(zB.[b2code]+ zB.[b3code]);.[c0code] <- p1+p4-p5+p7+zC.[c0code];.[c1code] <- p3+p5+zC.[c1code];.[c2code] <- p2+p4+zC.[c2code];.[c3code] <- p1-p2+p3+p6+zC.[c3code];(ZCode,MaskBits)(ZCode,MaskBits)(ZCode,MaskBits)n = 512 //1024,2048,4096mutable rand= new Random()rand1 = ref randGenerate i j (rand: Random ref) =.Value <- new Random(i+j)x = rand.Value.NextDouble()A = Array2D.init n n (fun i j -> Generate i j rand1)B = Array2D.init n n (fun i j -> Generate i j rand1)C = Array2D.create n n 0.0"[Lib multiply of %dx%d matrix] " n nx =A1= Math.Matrix.of_array2 AB1= Math.Matrix.of_array2 B(fun () -> MultiplyX A1 B1)|>ignore.GC.Collect()(Za,Zb,Zc) = CreateZMatrix A B CZc1= Array.copy ZcZc2= Array.copy ZcZc3= Array.copy Zc"[Ordinary multiply of %dx%d matrix] " n n(fun () -> Multiply A B C) |> ignore"[Fast multiply of %dx%d matrix] " n n(fun () -> PFXMultiply A B C)|>ignore"[Z multiply of %dx%d matrix] " n nx0 =Math.Vector.of_array (Time(fun () ->ZMatrixMultiply Za Zb Zc))"[Parallel Z multiply of %dx%d matrix] " n nx1 =Math.Vector.of_array (Time(fun () ->PZMatrixMultiply Za Zb Zc1))"[Strassen multiply of %dx%d matrix] " n nx2 =Math.Vector.of_array (Time(fun () ->StrassenMultiply Za Zb Zc2))"[Parallel Strassen multiply of %dx%d matrix] " n nx3 =Math.Vector.of_array (Time(fun () ->ParStrassenMultiply Za Zb Zc3))error = (x0-x2)+(x1-x3)"error = ".Write(Array.sum (Math.Vector.to_array error))PrintWithHeading s =line = String.replicate(s |> String.length) "=""%s\n%s" s line"RFE 2010\nVladimir Shchur\n""Matrix Multiply"()"\n\nPress any key to finish"

ПРИЛОЖЕНИЕ 2

Программа по обработке графического изображения множества Мандельброта

.fs - файл запуска Windows-приложения

module Program =SystemSystem.Windows.FormsMandelbrotFormModule

#if COMPILED

[<STAThread>]Application.EnableVisualStyles()Application.SetCompatibleTextRenderingDefault(false)Application.Run(new MandelbrotForm())

#endif.fs -в этом файле производятся обработка пользовательских событий и вывод изображения на экран

module MandelbrotFormModuleSystemSystem.Windows.FormsSystem.DrawingSystem.Drawing.ImagingSystem.DiagnosticsSystem.Runtime.InteropServicesSystem.ThreadingSystem.Threading.TasksSystem.Collections.ConcurrentSystem.IOMandelbrotGeneratorModule

/// <summary>Describes the bounds of the fractal to render.</summary>mutable _mandelbrotWindow = MandelbrotPosition( 2.9, 2.27, -0.75, 0.006)

/// <summary>The last known size of the main window.</summary>mutable _lastWindowSize = Size.Empty

/// <summary>The last known position of the mouse.</summary>mutable _lastMousePosition = Point(0,0)

/// <summary>The most recent cancellation source to cancel the last task.</summary>mutable _lastCancellation = new CancellationTokenSource()

/// <summary>The last time the image was updated.</summary>mutable _lastUpdateTime = DateTime.MinValue

/// <summary>Whether the left mouse button is currently pressed on the picture box.</summary>mutable _leftMouseDown = false

/// <summary>

/// The format string to use for the main form's title; {0} should be set to the number of

/// pixels per second rendered.

/// </summary>_formTitle = "Interactive Fractal F# ({0}x) - PPMS: {1} - Time: {2}";

/// <summary>Whether to use parallel rendering.</summary>mutable _parallelRendering = false;MandelbrotForm() as this =Form(ClientSize = new System.Drawing.Size(521, 452),= new System.Drawing.SizeF(8.0f, 16.0f),= System.Windows.Forms.AutoScaleMode.Font,= new System.Windows.Forms.Padding(4, 4, 4, 4),= "MainForm",= "Mandelbrot in F#")pictureBox = new PictureBox(BackColor = System.Drawing.Color.Black,= System.Windows.Forms.DockStyle.Fill,= Point(0, 0),= Padding(4, 4, 4, 4),= "mandelbrotPb",= Size(410, 369),= System.Windows.Forms.PictureBoxSizeMode.CenterImage,= 0,= false)statusStrip = new StatusStrip( Location = Point(0, 427),= "statusStrip",= Padding(1, 0, 19, 0),= Size(521, 25),= 2,= "statusStrip")toolStripStatusLabel = new ToolStripStatusLabel(Name = "toolStripStatusLabel1",= Size(386, 20),= "P: parallel mode, S: sequential mode, Double-click: zoom")countProc flag =flag with

| false -> 1

| true -> Environment.ProcessorCountUpdateImageAsync () =

// If there's currently an active task, cancel it! We don't care about it anymore.not (_lastCancellation.Equals(null))_lastCancellation.Cancel()

// Get the current size of the picture boxrenderSize = pictureBox.Size

// Keep track of the time this request was made. If multiple requests are executing,

// we want to only render the most recent one available rather than overwriting a more

// recent image with an older one.timeOfRequest = DateTime.UtcNow;

// Start a task to asynchronously render the fractal, and store the task

// so we can cancel it later as necessary

_lastCancellation <- new CancellationTokenSource()token = _lastCancellation.Token

// Start a task to asynchronously render the fractaltask ={

// For diagnostic reasons, time how long the rendering takessw = Stopwatch.StartNew()

// Render the fractalbmp = Create _mandelbrotWindow renderSize.Width renderSize.Height token _parallelRenderingnot (bmp.Equals(null))sw.Stop()ppms = (Convert.ToDouble(renderSize.Width * renderSize.Height)) / (double) sw.ElapsedMilliseconds;

// Update the fractal image asynchronously on the UI

// If this image is the most recent, store it into the picture box

// making sure to free the resources for the one currently in use.

// And update the form's title to reflect the rendering time.(timeOfRequest > _lastUpdateTime)//pictureBox.Image.Dispose().Image <- bmp

//_lastUpdateTime <- timeOfRequest.Text <- String.Format(_formTitle,_parallelRendering,.ToString("F2"), sw.ElapsedMilliseconds.ToString())file = new FileStream("D:/Result/F#.txt", FileMode.Append)strw = new StreamWriter(file).WriteLine(this.Text).Flush().Close()

// If the image isn't the most recent, just get rid of itbmp.Dispose()

}.StartAsTask(task,cancellationToken = token) |> ignore

// Add Handlersthis.SuspendLayout()this.Controls.Add(pictureBox)statusStrip.Items.Add(toolStripStatusLabel)|>ignorethis.Controls.Add(statusStrip)pictureBox.VisibleChanged.AddHandler(new EventHandler(fun s e -> this.pictureBox_VisibleChanged (s,e)))pictureBox.MouseDoubleClick.AddHandler(new MouseEventHandler(fun s e -> this.pictureBox_DoubleClick(s,e)))pictureBox.MouseDown.AddHandler(new MouseEventHandler(fun s e -> this.pictureBox_MouseDown(s,e)))pictureBox.MouseUp.AddHandler(new MouseEventHandler(fun s e -> this.pictureBox_MouseUp(s,e)))pictureBox.MouseMove.AddHandler(new MouseEventHandler(fun s e -> this.pictureBox_MouseMove(s,e)))pictureBox.Resize.AddHandler(new EventHandler(fun s e -> this.pictureBox_Resize(s,e)))this.ResumeLayout()this.pictureBox_VisibleChanged (s, e) =(pictureBox.Visible)_lastWindowSize <- this.Size|> ignorethis.pictureBox_DoubleClick (s, e) =

// Center the image on the selected location

_mandelbrotWindow.CenterX <- _mandelbrotWindow.CenterX + (float (e.X - (pictureBox.Width / 2)) / (float pictureBox.Width)) * _mandelbrotWindow.Width

_mandelbrotWindow.CenterY <- _mandelbrotWindow.CenterY + (float (e.Y - (pictureBox.Height / 2)) / (float pictureBox.Height)) * _mandelbrotWindow.Height

// If the left mouse button was used, zoom in by a factor of 2; if the right mouse button, zoom

// out by a factor of 2factor =(e.Button = MouseButtons.Left)0.52.0;

_mandelbrotWindow.Width <- _mandelbrotWindow.Width*factor

_mandelbrotWindow.Height <- _mandelbrotWindow.Height*factor

// Update the image()this.pictureBox_MouseDown (s, e) =

// Record that mouse button is being pressed(e.Button = MouseButtons.Left)_lastMousePosition <- e.Location

_leftMouseDown <- truethis.pictureBox_MouseUp (s, e) =

// Record that the mouse button is being released(e.Button = MouseButtons.Left)_lastMousePosition <- e.Location

_leftMouseDown <- falsethis.pictureBox_MouseMove (s, e) =

// Determine how far the mouse has moved. If it moved at all...delta = new Point(e.X - _lastMousePosition.X, e.Y - _lastMousePosition.Y)not (delta = Point.Empty)// And if the left mouse button is down...(_leftMouseDown)

// Determine how much the mouse moved in fractal coordinatesfractalMoveX = (float delta.X) * _mandelbrotWindow.Width / (float pictureBox.Width)fractalMoveY = (float delta.Y) * _mandelbrotWindow.Height / (float pictureBox.Height)

// Shift the fractal window accordingly

_mandelbrotWindow.CenterX <- _mandelbrotWindow.CenterX - fractalMoveX

_mandelbrotWindow.CenterY <- _mandelbrotWindow.CenterY - fractalMoveY

// And update the image()

// Record the new mouse position

_lastMousePosition <- e.Locationthis.pictureBox_Resize (s, e) =

// If the window has been resizednot (this.Size = _lastWindowSize)

// Scale the mandelbrot image by the same factor so that its visual size doesn't changenot (_lastWindowSize.Width = 0)xFactor = (float this.Size.Width) / (float _lastWindowSize.Width)

_mandelbrotWindow.Width <- _mandelbrotWindow.Width * xFactornot (_lastWindowSize.Height = 0)yFactor = (float this.Size.Height) / (float _lastWindowSize.Height)

_mandelbrotWindow.Height <- _mandelbrotWindow.Height * yFactor

// Record the new window size

_lastWindowSize <- this.Size

// Update the image()this.OnKeyDown e =

// Handle the key pressed.OnKeyDown ee.KeyCode with.R ->

_mandelbrotWindow <- new MandelbrotPosition( 2.9, 2.27, -0.75, 0.006)tempForm = new MandelbrotForm()xFactor = (float this.Size.Width) / (float tempForm.Width)yFactor = (float this.Size.Height) / (float tempForm.Height)

_mandelbrotWindow.Width <- _mandelbrotWindow.Width * xFactor

_mandelbrotWindow.Height <- _mandelbrotWindow.Height * yFactor()

|Keys.S ->

_parallelRendering <- false()

|Keys.P ->

_parallelRendering <- true()

|_ -> ().fs -в этом файле производятся расчеты цвета пикселей для построения множества Мандельброта

module MandelbrotGeneratorModule

#nowarn "9"SystemSystem.IOSystem.Windows.FormsSystem.DrawingSystem.Drawing.ImagingSystem.DiagnosticsSystem.Runtime.InteropServicesSystem.ThreadingSystem.Threading.TasksSystem.NumericsMicrosoft.FSharp.NativeInteropMicrosoft.FSharp.CollectionsSystem.Collections.Concurrent

/// <summary>Represents the bounds and location of the mandelbrot fractal to be rendered.</summary>public MandelbrotPosition =mutable public Width: floatmutable public Height: floatmutable public CenterX: floatmutable public CenterY: float(width: float, height: float, centerX: float, centerY: float) =

{ Width = width ; Height = height; CenterX = centerX; CenterY = centerY }

/// <summary>Create the color palette to be used for all fractals.</summary>

/// <returns>A 256-color array that can be stored into an 8bpp Bitmap's ColorPalette.</returns>CreatePaletteColors : Color[] =paletteColors : Color[] = Array.init 256 (fun i -> Color.FromArgb(0, i * 5 % 256, i * 5 % 256))

/// <summary>The 256 color palette to use for all fractals.</summary>_paletteColors = CreatePaletteColors

/// <summary>Copy our precreated color palette into the target Bitmap.</summary>

/// <param name="bmp">The Bitmap to be updated.</param>UpdatePalette (bmp : Bitmap) =p = bmp.Palette.Array.Copy(_paletteColors, p.Entries, _paletteColors.Length).Palette <- p// The Bitmap will only update when the Palette property's setter is used

/// <summary>Renders a mandelbrot fractal.</summary>

/// <param name="position">The MandelbrotPosition representing the fractal boundaries to be rendered.</param>

/// <param name="imageWidth">The width in pixels of the image to create.</param>

/// <param name="imageHeight">The height in pixels of the image to create.</param>

/// <param name="parallelRendering">Whether to render the image in parallel.</param>

/// <returns>The rendered Bitmap.</returns>Create (position : MandelbrotPosition ) imageWidth (imageHeight : int) (cancellationToken: CancellationToken) parallelRendering =

// The maximum number of iterations to perform for each pixel. Higher number means better

// quality but also slower.maxIterations = 256

// In order to use the Bitmap ctor that accepts a stride, the stride must be divisible by four.

// We're using imageWidth as the stride, so shift it to be divisible by 4 as necessary.newImageWidth =imageWidth % 4 = 0imageWidth(imageWidth / 4) * 4

// Based on the fractal bounds, determine its upper left coordinateleft = position.CenterX - (position.Width / 2.0)top = position.CenterY - (position.Height / 2.0)

// Get the factors that can be multiplied by row and col to arrive at specific x and y valuescolToXTranslation = position.Width / (float newImageWidth)rowToYTranslation = position.Height / (float imageHeight)

// Get Pixel Color for each complex numberrec drawBit (z : Complex) c curIter =curIter withwhen x = maxIterations ->byte 0

|_ ->z withwhen x.Magnitude > 4.0 -> byte curIter

|_ -> drawBit (z*z+c) c (curIter+1)getbyte initialY j =.ThrowIfCancellationRequested()c = new Complex((float j) * colToXTranslation + left, initialY)c c 0

// Fill dataArray with pixel colorsdata =parallelRendering then.Parallel.init imageHeight (fun i -> Array.init newImageWidth (fun j -> getbyte ((float i) * rowToYTranslation + top) j)).init imageHeight (fun i -> Array.init newImageWidth (fun j -> getbyte ((float i) * rowToYTranslation + top) j))

// Create the bitmapbitMap = new Bitmap(newImageWidth,imageHeight,PixelFormat.Format8bppIndexed)

// Get the bitmap data for bitmap with a Read Write lockbitData = bitMap.LockBits(Rectangle(0,0,bitMap.Width,bitMap.Height),ImageLockMode.ReadWrite,PixelFormat.Format8bppIndexed)

// Setup the pointermutable (p:nativeptr<byte>) = NativePtr.ofNativeInt (bitData.Scan0)i in 0..bitMap.Height-1 doj in 0..bitMap.Width-1 do.set p 0 (data.[i].[j])<- NativePtr.add p 1tempBitmap = new Bitmap(newImageWidth,imageHeight,newImageWidth,PixelFormat.Format8bppIndexed,bitData.Scan0)