ЛИТЕРАТУРА
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)