Skip to content

Instantly share code, notes, and snippets.

@sqeezy
Last active October 10, 2017 12:38
Show Gist options
  • Save sqeezy/b606c3042543f997fbd24d64a5030bcd to your computer and use it in GitHub Desktop.
Save sqeezy/b606c3042543f997fbd24d64a5030bcd to your computer and use it in GitHub Desktop.
open System
type Agent<'T> = MailboxProcessor<'T>
let maxFloat = Double.MaxValue
let ran = Random 42
let randomFloat ()=
float(ran.Next(-10000000,10000000))
type MsgType =
| Finish
| UpdateGlobal of float
| Start
type GlobalStateApi =
|Register of Agent<MsgType>
|NewGlobalBest of float
|Start
type WorkerState =
{GlobalStateAgent : Agent<GlobalStateApi>;
LocalBest : float;
GlobalBest : float;
Running : bool
}
with
static member Create agent globalBest =
{LocalBest=globalBest;GlobalBest=globalBest;GlobalStateAgent=agent; Running = false}
member this.UpdateLocalBest value = {LocalBest=value;GlobalBest=this.GlobalBest;GlobalStateAgent=this.GlobalStateAgent;Running = this.Running}
member this.UpdateGlobalBest value = {LocalBest=this.LocalBest;GlobalBest=value;GlobalStateAgent=this.GlobalStateAgent;Running = this.Running}
member this.Start = {LocalBest=this.LocalBest;GlobalBest=this.GlobalBest;GlobalStateAgent=this.GlobalStateAgent;Running = true}
let Worker globalStateAgent = Agent.Start(fun inbox ->
let rec loop (state:WorkerState) = async{
let! msg = inbox.TryReceive(1)
match msg with
|Some (value : MsgType) ->
match value with
|MsgType.Start -> return! loop state.Start
|Finish -> return ()
|UpdateGlobal newGlobal ->
let newState = state.UpdateGlobalBest newGlobal
return! loop newState
|None ->
if state.Running then
let newTest = randomFloat()
if newTest < state.LocalBest then
let newState = state.UpdateLocalBest newTest
if newTest < state.GlobalBest then
state.GlobalStateAgent.Post(NewGlobalBest newTest)
return! loop newState
return! loop state
}
let initialState = (WorkerState.Create globalStateAgent maxFloat)
loop initialState
)
type GlobalState = {Agents : Agent<MsgType> list;GlobalBest : float} with
member this.UpdateBest newBest = {Agents=this.Agents;GlobalBest =newBest}
member this.AddAgent agent = {Agents=agent::this.Agents;GlobalBest=this.GlobalBest}
let GlobalStateAgent () =
Agent.Start(fun inbox ->
let sendNewBestToAllAgents (agents:list<Agent<MsgType>>) best =
let sendNewBestToAgent agent = (agent:Agent<MsgType>).Post(UpdateGlobal best)
agents |> List.map sendNewBestToAgent
let rec loop state =
async{
let! msg = inbox.TryReceive(1)
match msg with
|Some call ->
match call with
|Register agent -> return! loop (state.AddAgent(agent):GlobalState)
|Start ->
let startAgent (agent : Agent<MsgType>) = agent.Post(MsgType.Start)
List.map startAgent state.Agents |> ignore
return! loop state
|NewGlobalBest value ->
match value < state.GlobalBest with
|true ->
sendNewBestToAllAgents state.Agents value |> ignore
printfn "New global best %A" value
return! loop (state.UpdateBest value)
|false ->
return! loop state
|None -> return! loop state
}
loop {Agents=[];GlobalBest=0.0}
)
[<EntryPoint>]
let main argv =
let hub = GlobalStateAgent()
let createWorker () = Worker hub
let register w = hub.Post(Register w)
let createAndRegister = createWorker >> register
[1..10]
|> fun _ -> createAndRegister()
hub.Post(Start)
while true do
Console.WriteLine "wait"
Threading.Thread.Sleep 1000
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment