MBrace.Core and MBrace.Azure


Example: Monte Carlo Pi Approximation

This example is from the MBrace Starter Kit.

In this example you learn you to perform distributed, multi-core CPU computations on your MBrace cluster.

The example implements the classic monte carlo implementation using MBrace. Take random points in the [0,1] x [0,1] square and count the occurences within the circle radius. The resulting fraction should estimate π / 4.

First, define a local, single-threaded Pi estimator:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
let localMonteCarloPiWorker (iterations : bigint) : bigint =
    let rand = new Random(obj().GetHashCode())
    let maxIter = bigint Int32.MaxValue
    let mutable rem = iterations
    let mutable acc = 0I
    while rem > 0I do
        // bigints are heap allocated so break iteration into smaller int segments
        let iter = min maxIter rem
        let mutable currAcc = 0
        for i = 1 to int iter do
            let x = rand.NextDouble()
            let y = rand.NextDouble()
            if x * x + y * y <= 1. then
                currAcc <- currAcc + 1

        acc <- acc + bigint currAcc
        rem <- rem - iter

    acc

Next, define a helper function to convert a bigint rational to floating point number:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let ratioToFloat divident divisor =
    let rec aux acc i dividend divisor =
        let div, rem = BigInteger.DivRem(dividend,divisor)
        if i = 15 || div = 0I && rem = 0I then acc else
        let dec = float div * Math.Pow(10., - float i) // div * 10^-i
        aux (acc + dec) (i + 1) (rem * 10I) divisor

    aux 0. 0 divident divisor

We are now ready to create the distributed component of our sample. Now calculate π using MBrace:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
let calculatePi (iterations : bigint) : Cloud<float> = cloud {
    let! workers = Cloud.GetAvailableWorkers()
    let totalCores = workers |> Array.sumBy (fun w -> w.ProcessorCount) |> bigint
    let iterationsPerCore = iterations / totalCores
    let rem = iterations % totalCores
    let partitions =
        [|
            for _ in 1I .. totalCores -> iterationsPerCore
            if rem > 1I then yield rem
        |]

    // perform the distributed sampling operation
    let! samples =
        CloudFlow.OfArray partitions
        |> CloudFlow.map localMonteCarloPiWorker
        |> CloudFlow.sum

    let ratio = ratioToFloat samples iterations
    return 4.0 * ratio
}

Start the cloud process:

1: 
let calcTask = cluster.CreateProcess(calculatePi 10000000000I)

Check on its progress:

1: 
2: 
cluster.ShowWorkers()
calcTask.ShowInfo()

Get the result:

1: 
calcTask.Result

In this example, you've learned how to run a CPU-intensive Monte Carlo algorithm on an MBrace cluster. Continue with further samples to learn more about the MBrace programming model.

Note, you can use the above techniques from both scripts and compiled projects. To see the components referenced by this script, see ThespianCluster.fsx or AzureCluster.fsx.

namespace System
namespace System.Numerics
namespace System.IO
namespace MBrace
namespace MBrace.Core
namespace MBrace.Flow
val cluster : MBrace.Thespian.ThespianCluster

Full name: 200-monte-carlo-pi-approximation-example.cluster
module Config
val GetCluster : unit -> MBrace.Thespian.ThespianCluster

Full name: Config.GetCluster


 Gets or creates a new Thespian cluster session.
val localMonteCarloPiWorker : iterations:bigint -> bigint

Full name: 200-monte-carlo-pi-approximation-example.localMonteCarloPiWorker
val iterations : bigint
type bigint = BigInteger

Full name: Microsoft.FSharp.Core.bigint
val rand : Random
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float

Full name: System.Random

--------------------
Random() : unit
Random(Seed: int) : unit
type obj = Object

Full name: Microsoft.FSharp.Core.obj
val maxIter : BigInteger
type Int32 =
  struct
    member CompareTo : value:obj -> int + 1 overload
    member Equals : obj:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member GetTypeCode : unit -> TypeCode
    member ToString : unit -> string + 3 overloads
    static val MaxValue : int
    static val MinValue : int
    static member Parse : s:string -> int + 3 overloads
    static member TryParse : s:string * result:int -> bool + 1 overload
  end

Full name: System.Int32
field int.MaxValue = 2147483647
val mutable rem : bigint
val mutable acc : BigInteger
val iter : BigInteger
val min : e1:'T -> e2:'T -> 'T (requires comparison)

Full name: Microsoft.FSharp.Core.Operators.min
val mutable currAcc : int
val i : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val x : float
Random.NextDouble() : float
val y : float
val ratioToFloat : divident:BigInteger -> divisor:BigInteger -> float

Full name: 200-monte-carlo-pi-approximation-example.ratioToFloat
val divident : BigInteger
val divisor : BigInteger
val aux : (float -> int -> BigInteger -> BigInteger -> float)
val acc : float
val dividend : BigInteger
val div : BigInteger
val rem : BigInteger
Multiple items
type BigInteger =
  struct
    new : value:int -> BigInteger + 7 overloads
    member CompareTo : other:int64 -> int + 3 overloads
    member Equals : obj:obj -> bool + 3 overloads
    member GetHashCode : unit -> int
    member IsEven : bool
    member IsOne : bool
    member IsPowerOfTwo : bool
    member IsZero : bool
    member Sign : int
    member ToByteArray : unit -> byte[]
    ...
  end

Full name: System.Numerics.BigInteger

--------------------
BigInteger()
BigInteger(value: int) : unit
BigInteger(value: uint32) : unit
BigInteger(value: int64) : unit
BigInteger(value: uint64) : unit
BigInteger(value: float32) : unit
BigInteger(value: float) : unit
BigInteger(value: decimal) : unit
BigInteger(value: byte []) : unit
BigInteger.DivRem(dividend: BigInteger, divisor: BigInteger, remainder: byref<BigInteger>) : BigInteger
val dec : float
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
type Math =
  static val PI : float
  static val E : float
  static member Abs : value:sbyte -> sbyte + 6 overloads
  static member Acos : d:float -> float
  static member Asin : d:float -> float
  static member Atan : d:float -> float
  static member Atan2 : y:float * x:float -> float
  static member BigMul : a:int * b:int -> int64
  static member Ceiling : d:decimal -> decimal + 1 overload
  static member Cos : d:float -> float
  ...

Full name: System.Math
Math.Pow(x: float, y: float) : float
val calculatePi : iterations:bigint -> 'a

Full name: 200-monte-carlo-pi-approximation-example.calculatePi
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val sumBy : projection:('T -> 'U) -> array:'T [] -> 'U (requires member ( + ) and member get_Zero)

Full name: Microsoft.FSharp.Collections.Array.sumBy
Multiple items
module CloudFlow

from MBrace.Flow

--------------------
type CloudFlow =
  static member OfArray : source:'T [] -> CloudFlow<'T>
  static member OfCloudArrays : cloudArrays:seq<#CloudArray<'T>> -> LocalCloud<PersistedCloudFlow<'T>>
  static member OfCloudCollection : collection:ICloudCollection<'T> * ?sizeThresholdPerWorker:(unit -> int64) -> CloudFlow<'T>
  static member OfCloudDirectory : dirPath:string * serializer:ISerializer * ?sizeThresholdPerCore:int64 -> CloudFlow<'T>
  static member OfCloudDirectory : dirPath:string * ?deserializer:(Stream -> seq<'T>) * ?sizeThresholdPerCore:int64 -> CloudFlow<'T>
  static member OfCloudDirectory : dirPath:string * deserializer:(TextReader -> seq<'T>) * ?encoding:Encoding * ?sizeThresholdPerCore:int64 -> CloudFlow<'T>
  static member OfCloudDirectoryByLine : dirPath:string * ?encoding:Encoding * ?sizeThresholdPerCore:int64 -> CloudFlow<string>
  static member OfCloudFileByLine : path:string * ?encoding:Encoding -> CloudFlow<string>
  static member OfCloudFileByLine : paths:seq<string> * ?encoding:Encoding * ?sizeThresholdPerCore:int64 -> CloudFlow<string>
  static member OfCloudFiles : paths:seq<string> * serializer:ISerializer * ?sizeThresholdPerCore:int64 -> CloudFlow<'T>
  ...

Full name: MBrace.Flow.CloudFlow

--------------------
type CloudFlow<'T> =
  interface
    abstract member WithEvaluators : collectorFactory:LocalCloud<Collector<'T,'S>> -> projection:('S -> LocalCloud<'R>) -> combiner:('R [] -> LocalCloud<'R>) -> Cloud<'R>
    abstract member DegreeOfParallelism : int option
  end

Full name: MBrace.Flow.CloudFlow<_>
static member CloudFlow.OfArray : source:'T [] -> CloudFlow<'T>
val map : f:('T -> 'R) -> flow:CloudFlow<'T> -> CloudFlow<'R>

Full name: MBrace.Flow.CloudFlow.map
val sum : flow:CloudFlow<'T> -> MBrace.Core.Cloud<'T> (requires member ( + ) and member get_Zero)

Full name: MBrace.Flow.CloudFlow.sum
val calcTask : MBrace.Runtime.CloudProcess<obj>

Full name: 200-monte-carlo-pi-approximation-example.calcTask
member MBrace.Runtime.MBraceClient.CreateProcess : workflow:MBrace.Core.Cloud<'T> * ?cancellationToken:MBrace.Core.ICloudCancellationToken * ?faultPolicy:MBrace.Core.FaultPolicy * ?target:MBrace.Core.IWorkerRef * ?additionalResources:MBrace.Core.Internals.ResourceRegistry * ?taskName:string -> MBrace.Runtime.CloudProcess<'T>
member MBrace.Runtime.MBraceClient.ShowWorkers : unit -> unit
member MBrace.Runtime.CloudProcess.ShowInfo : unit -> unit
property MBrace.Runtime.CloudProcess.Result: obj
Fork me on GitHub