From 8e112ff67c46ea370bccd4b7dc1f6848b594a500 Mon Sep 17 00:00:00 2001 From: Parzival-05 Date: Tue, 24 Dec 2024 03:56:56 +0300 Subject: [PATCH] Autoformat --- VSharp.Explorer/AISearcher.fs | 506 +++++++++++++++------------ VSharp.Explorer/Explorer.fs | 517 +++++++++++++++++----------- VSharp.Explorer/Options.fs | 82 +++-- VSharp.ML.GameServer.Runner/Main.fs | 370 +++++++++++--------- 4 files changed, 859 insertions(+), 616 deletions(-) diff --git a/VSharp.Explorer/AISearcher.fs b/VSharp.Explorer/AISearcher.fs index 3ab737062..629a8c4b1 100644 --- a/VSharp.Explorer/AISearcher.fs +++ b/VSharp.Explorer/AISearcher.fs @@ -6,192 +6,250 @@ open VSharp open VSharp.IL.Serializer open VSharp.ML.GameServer.Messages -type internal AISearcher(oracle: Oracle, aiAgentTrainingOptions: Option) = +type internal AISearcher(oracle : Oracle, aiAgentTrainingOptions : Option) = let stepsToSwitchToAI = match aiAgentTrainingOptions with | None -> 0u | Some options -> options.stepsToSwitchToAI - + let stepsToPlay = match aiAgentTrainingOptions with | None -> 0u | Some options -> options.stepsToPlay - - let mutable lastCollectedStatistics = Statistics() + + let mutable lastCollectedStatistics = + Statistics () let mutable defaultSearcherSteps = 0u - let mutable (gameState:Option) = None - let mutable useDefaultSearcher = stepsToSwitchToAI > 0u + let mutable (gameState : Option) = + None + let mutable useDefaultSearcher = + stepsToSwitchToAI > 0u let mutable afterFirstAIPeek = false - let mutable incorrectPredictedStateId = false + let mutable incorrectPredictedStateId = + false let defaultSearcher = match aiAgentTrainingOptions with - | None -> BFSSearcher() :> IForwardSearcher + | None -> BFSSearcher () :> IForwardSearcher | Some options -> match options.defaultSearchStrategy with - | BFSMode -> BFSSearcher() :> IForwardSearcher - | DFSMode -> DFSSearcher() :> IForwardSearcher - | x -> failwithf $"Unexpected default searcher {x}. DFS and BFS supported for now." + | BFSMode -> BFSSearcher () :> IForwardSearcher + | DFSMode -> DFSSearcher () :> IForwardSearcher + | x -> failwithf $"Unexpected default searcher {x}. DFS and BFS supported for now." let mutable stepsPlayed = 0u - let isInAIMode () = (not useDefaultSearcher) && afterFirstAIPeek - let q = ResizeArray<_>() - let availableStates = HashSet<_>() - let updateGameState (delta:GameState) = - match gameState with - | None -> - gameState <- Some delta - | Some s -> - let updatedBasicBlocks = delta.GraphVertices |> Array.map (fun b -> b.Id) |> HashSet - let updatedStates = delta.States |> Array.map (fun s -> s.Id) |> HashSet - let vertices = - s.GraphVertices - |> Array.filter (fun v -> updatedBasicBlocks.Contains v.Id |> not) - |> ResizeArray<_> - vertices.AddRange delta.GraphVertices - let edges = - s.Map - |> Array.filter (fun e -> updatedBasicBlocks.Contains e.VertexFrom |> not) + let isInAIMode () = + (not useDefaultSearcher) && afterFirstAIPeek + let q = ResizeArray<_> () + let availableStates = HashSet<_> () + let updateGameState (delta : GameState) = + match gameState with + | None -> gameState <- Some delta + | Some s -> + let updatedBasicBlocks = + delta.GraphVertices |> Array.map (fun b -> b.Id) |> HashSet + let updatedStates = + delta.States |> Array.map (fun s -> s.Id) |> HashSet + let vertices = + s.GraphVertices + |> Array.filter (fun v -> updatedBasicBlocks.Contains v.Id |> not) + |> ResizeArray<_> + vertices.AddRange delta.GraphVertices + let edges = + s.Map + |> Array.filter (fun e -> updatedBasicBlocks.Contains e.VertexFrom |> not) + |> ResizeArray<_> + edges.AddRange delta.Map + let activeStates = + vertices |> Seq.collect (fun v -> v.States) |> HashSet + + let states = + let part1 = + s.States + |> Array.filter (fun s -> activeStates.Contains s.Id && (not <| updatedStates.Contains s.Id)) |> ResizeArray<_> - edges.AddRange delta.Map - let activeStates = vertices |> Seq.collect (fun v -> v.States) |> HashSet - - let states = - let part1 = - s.States - |> Array.filter (fun s -> activeStates.Contains s.Id && (not <| updatedStates.Contains s.Id)) - |> ResizeArray<_> - - part1.AddRange delta.States - - part1.ToArray() - |> Array.map (fun s -> State(s.Id - , s.Position - , s.PathConditionSize - , s.VisitedAgainVertices - , s.VisitedNotCoveredVerticesInZone - , s.VisitedNotCoveredVerticesOutOfZone - , s.StepWhenMovedLastTime - , s.InstructionsVisitedInCurrentBlock - , s.History - , s.Children |> Array.filter activeStates.Contains) + + part1.AddRange delta.States + + part1.ToArray () + |> Array.map (fun s -> + State ( + s.Id, + s.Position, + s.PathConditionSize, + s.VisitedAgainVertices, + s.VisitedNotCoveredVerticesInZone, + s.VisitedNotCoveredVerticesOutOfZone, + s.StepWhenMovedLastTime, + s.InstructionsVisitedInCurrentBlock, + s.History, + s.Children |> Array.filter activeStates.Contains ) - - gameState <- Some <| GameState (vertices.ToArray(), states, edges.ToArray()) - - + ) + + gameState <- Some <| GameState (vertices.ToArray (), states, edges.ToArray ()) + + let init states = q.AddRange states - defaultSearcher.Init q + defaultSearcher.Init q states |> Seq.iter (availableStates.Add >> ignore) let reset () = - defaultSearcher.Reset() + defaultSearcher.Reset () defaultSearcherSteps <- 0u - lastCollectedStatistics <- Statistics() + lastCollectedStatistics <- Statistics () gameState <- None afterFirstAIPeek <- false incorrectPredictedStateId <- false useDefaultSearcher <- stepsToSwitchToAI > 0u - q.Clear() - availableStates.Clear() + q.Clear () + availableStates.Clear () let update (parent, newSates) = - if useDefaultSearcher - then defaultSearcher.Update (parent,newSates) + if useDefaultSearcher then + defaultSearcher.Update (parent, newSates) newSates |> Seq.iter (availableStates.Add >> ignore) let remove state = - if useDefaultSearcher - then defaultSearcher.Remove state + if useDefaultSearcher then + defaultSearcher.Remove state let removed = availableStates.Remove state - assert removed - for bb in state._history do bb.Key.AssociatedStates.Remove state |> ignore - - let inTrainMode = aiAgentTrainingOptions.IsSome - + assert removed + for bb in state._history do + bb.Key.AssociatedStates.Remove state |> ignore + + let inTrainMode = + aiAgentTrainingOptions.IsSome + let pick selector = - if useDefaultSearcher - then + if useDefaultSearcher then defaultSearcherSteps <- defaultSearcherSteps + 1u - if Seq.length availableStates > 0 - then - let gameStateDelta = collectGameStateDelta () + if Seq.length availableStates > 0 then + let gameStateDelta = + collectGameStateDelta () updateGameState gameStateDelta - let statistics = computeStatistics gameState.Value - Application.applicationGraphDelta.Clear() + let statistics = + computeStatistics gameState.Value + Application.applicationGraphDelta.Clear () lastCollectedStatistics <- statistics useDefaultSearcher <- defaultSearcherSteps < stepsToSwitchToAI - defaultSearcher.Pick() - elif Seq.length availableStates = 0 - then None - elif Seq.length availableStates = 1 - then Some (Seq.head availableStates) + defaultSearcher.Pick () + elif Seq.length availableStates = 0 then + None + elif Seq.length availableStates = 1 then + Some (Seq.head availableStates) else - let gameStateDelta = collectGameStateDelta () + let gameStateDelta = + collectGameStateDelta () updateGameState gameStateDelta - let statistics = computeStatistics gameState.Value - if isInAIMode() - then - let reward = computeReward lastCollectedStatistics statistics + let statistics = + computeStatistics gameState.Value + if isInAIMode () then + let reward = + computeReward lastCollectedStatistics statistics oracle.Feedback (Feedback.MoveReward reward) - Application.applicationGraphDelta.Clear() - if inTrainMode && stepsToPlay = stepsPlayed - then None + Application.applicationGraphDelta.Clear () + if inTrainMode && stepsToPlay = stepsPlayed then + None else - let toPredict = - if inTrainMode && stepsPlayed > 0u - then gameStateDelta - else gameState.Value + let toPredict = + if inTrainMode && stepsPlayed > 0u then + gameStateDelta + else + gameState.Value let stateId = oracle.Predict toPredict afterFirstAIPeek <- true - let state = availableStates |> Seq.tryFind (fun s -> s.internalId = stateId) + let state = + availableStates |> Seq.tryFind (fun s -> s.internalId = stateId) lastCollectedStatistics <- statistics stepsPlayed <- stepsPlayed + 1u match state with - | Some state -> - Some state + | Some state -> Some state | None -> incorrectPredictedStateId <- true oracle.Feedback (Feedback.IncorrectPredictedStateId stateId) None - new (pathToONNX:string) = + new(pathToONNX : string) = let numOfVertexAttributes = 7 let numOfStateAttributes = 7 let numOfHistoryEdgeAttributes = 2 - let createOracle (pathToONNX: string) = - let sessionOptions = new SessionOptions() + let createOracle (pathToONNX : string) = + let sessionOptions = new SessionOptions () sessionOptions.ExecutionMode <- ExecutionMode.ORT_PARALLEL sessionOptions.GraphOptimizationLevel <- GraphOptimizationLevel.ORT_ENABLE_ALL - let session = new InferenceSession(pathToONNX, sessionOptions) - let runOptions = new RunOptions() - let feedback (x:Feedback) = () - let predict (gameState:GameState) = - let stateIds = Dictionary,int>() - let verticesIds = Dictionary,int>() + let session = + new InferenceSession (pathToONNX, sessionOptions) + let runOptions = new RunOptions () + let feedback (x : Feedback) = () + let predict (gameState : GameState) = + let stateIds = + Dictionary, int> () + let verticesIds = + Dictionary, int> () let networkInput = - let res = Dictionary<_,_>() + let res = Dictionary<_, _> () let gameVertices = - let shape = [| int64 gameState.GraphVertices.Length; numOfVertexAttributes |] - let attributes = Array.zeroCreate (gameState.GraphVertices.Length * numOfVertexAttributes) - for i in 0..gameState.GraphVertices.Length - 1 do + let shape = + [| + int64 gameState.GraphVertices.Length + numOfVertexAttributes + |] + let attributes = + Array.zeroCreate (gameState.GraphVertices.Length * numOfVertexAttributes) + for i in 0 .. gameState.GraphVertices.Length - 1 do let v = gameState.GraphVertices.[i] - verticesIds.Add(v.Id, i) + verticesIds.Add (v.Id, i) let j = i * numOfVertexAttributes - attributes.[j] <- float32 <| if v.InCoverageZone then 1u else 0u + attributes.[j] <- + float32 + <| if v.InCoverageZone then + 1u + else + 0u attributes.[j + 1] <- float32 <| v.BasicBlockSize - attributes.[j + 2] <- float32 <| if v.CoveredByTest then 1u else 0u - attributes.[j + 3] <- float32 <| if v.VisitedByState then 1u else 0u - attributes.[j + 4] <- float32 <| if v.TouchedByState then 1u else 0u - attributes.[j + 5] <- float32 <| if v.ContainsCall then 1u else 0u - attributes.[j + 6] <- float32 <| if v.ContainsThrow then 1u else 0u - OrtValue.CreateTensorValueFromMemory(attributes, shape) - + attributes.[j + 2] <- + float32 + <| if v.CoveredByTest then + 1u + else + 0u + attributes.[j + 3] <- + float32 + <| if v.VisitedByState then + 1u + else + 0u + attributes.[j + 4] <- + float32 + <| if v.TouchedByState then + 1u + else + 0u + attributes.[j + 5] <- + float32 + <| if v.ContainsCall then + 1u + else + 0u + attributes.[j + 6] <- + float32 + <| if v.ContainsThrow then + 1u + else + 0u + OrtValue.CreateTensorValueFromMemory (attributes, shape) + let states, numOfParentOfEdges, numOfHistoryEdges = let mutable numOfParentOfEdges = 0 let mutable numOfHistoryEdges = 0 - let shape = [| int64 gameState.States.Length; numOfStateAttributes |] - let attributes = Array.zeroCreate (gameState.States.Length * numOfStateAttributes) - for i in 0..gameState.States.Length - 1 do + let shape = + [| + int64 gameState.States.Length + numOfStateAttributes + |] + let attributes = + Array.zeroCreate (gameState.States.Length * numOfStateAttributes) + for i in 0 .. gameState.States.Length - 1 do let v = gameState.States.[i] numOfHistoryEdges <- numOfHistoryEdges + v.History.Length numOfParentOfEdges <- numOfParentOfEdges + v.Children.Length - stateIds.Add(v.Id,i) + stateIds.Add (v.Id, i) let j = i * numOfStateAttributes attributes.[j] <- float32 v.Position attributes.[j + 1] <- float32 v.PathConditionSize @@ -200,123 +258,137 @@ type internal AISearcher(oracle: Oracle, aiAgentTrainingOptions: Option Array.iteri ( - fun i e -> - index[i] <- int64 verticesIds[e.VertexFrom] - index[gameState.Map.Length + i] <- int64 verticesIds[e.VertexTo] - attributes[i] <- int64 e.Label.Token - ) - - OrtValue.CreateTensorValueFromMemory(index, shapeOfIndex) - , OrtValue.CreateTensorValueFromMemory(attributes, shapeOfAttributes) - + |> Array.iteri (fun i e -> + index[i] <- int64 verticesIds[e.VertexFrom] + index[gameState.Map.Length + i] <- int64 verticesIds[e.VertexTo] + attributes[i] <- int64 e.Label.Token + ) + + OrtValue.CreateTensorValueFromMemory (index, shapeOfIndex), + OrtValue.CreateTensorValueFromMemory (attributes, shapeOfAttributes) + let historyEdgesIndex_vertexToState, historyEdgesAttributes, parentOfEdges = - let shapeOfParentOf = [| 2L; numOfParentOfEdges |] - let parentOf = Array.zeroCreate (2 * numOfParentOfEdges) - let shapeOfHistory = [|2L; numOfHistoryEdges|] - let historyIndex_vertexToState = Array.zeroCreate (2 * numOfHistoryEdges) - let shapeOfHistoryAttributes = [| int64 numOfHistoryEdges; int64 numOfHistoryEdgeAttributes |] - let historyAttributes = Array.zeroCreate (2 * numOfHistoryEdges) + let shapeOfParentOf = + [| 2L ; numOfParentOfEdges |] + let parentOf = + Array.zeroCreate (2 * numOfParentOfEdges) + let shapeOfHistory = + [| 2L ; numOfHistoryEdges |] + let historyIndex_vertexToState = + Array.zeroCreate (2 * numOfHistoryEdges) + let shapeOfHistoryAttributes = + [| + int64 numOfHistoryEdges + int64 numOfHistoryEdgeAttributes + |] + let historyAttributes = + Array.zeroCreate (2 * numOfHistoryEdges) let mutable firstFreePositionInParentsOf = 0 - let mutable firstFreePositionInHistoryIndex = 0 - let mutable firstFreePositionInHistoryAttributes = 0 + let mutable firstFreePositionInHistoryIndex = + 0 + let mutable firstFreePositionInHistoryAttributes = + 0 gameState.States |> Array.iter (fun state -> - state.Children - |> Array.iteri (fun i children -> - let j = firstFreePositionInParentsOf + i - parentOf[j] <- int64 stateIds[state.Id] - parentOf[numOfParentOfEdges + j] <- int64 stateIds[children] - ) - firstFreePositionInParentsOf <- firstFreePositionInParentsOf + state.Children.Length - state.History - |> Array.iteri (fun i historyElem -> - let j = firstFreePositionInHistoryIndex + i - historyIndex_vertexToState[j] <- int64 verticesIds[historyElem.GraphVertexId] - historyIndex_vertexToState[numOfHistoryEdges + j] <- int64 stateIds[state.Id] - - let j = firstFreePositionInHistoryAttributes + numOfHistoryEdgeAttributes * i - historyAttributes[j] <- int64 historyElem.NumOfVisits - historyAttributes[j + 1] <- int64 historyElem.StepWhenVisitedLastTime - ) - firstFreePositionInHistoryIndex <- firstFreePositionInHistoryIndex + state.History.Length - firstFreePositionInHistoryAttributes <- firstFreePositionInHistoryAttributes + numOfHistoryEdgeAttributes * state.History.Length - ) - - OrtValue.CreateTensorValueFromMemory(historyIndex_vertexToState, shapeOfHistory) - , OrtValue.CreateTensorValueFromMemory(historyAttributes, shapeOfHistoryAttributes) - , OrtValue.CreateTensorValueFromMemory(parentOf, shapeOfParentOf) - + state.Children + |> Array.iteri (fun i children -> + let j = firstFreePositionInParentsOf + i + parentOf[j] <- int64 stateIds[state.Id] + parentOf[numOfParentOfEdges + j] <- int64 stateIds[children] + ) + firstFreePositionInParentsOf <- firstFreePositionInParentsOf + state.Children.Length + state.History + |> Array.iteri (fun i historyElem -> + let j = firstFreePositionInHistoryIndex + i + historyIndex_vertexToState[j] <- int64 verticesIds[historyElem.GraphVertexId] + historyIndex_vertexToState[numOfHistoryEdges + j] <- int64 stateIds[state.Id] + + let j = + firstFreePositionInHistoryAttributes + numOfHistoryEdgeAttributes * i + historyAttributes[j] <- int64 historyElem.NumOfVisits + historyAttributes[j + 1] <- int64 historyElem.StepWhenVisitedLastTime + ) + firstFreePositionInHistoryIndex <- firstFreePositionInHistoryIndex + state.History.Length + firstFreePositionInHistoryAttributes <- + firstFreePositionInHistoryAttributes + + numOfHistoryEdgeAttributes * state.History.Length + ) + + OrtValue.CreateTensorValueFromMemory (historyIndex_vertexToState, shapeOfHistory), + OrtValue.CreateTensorValueFromMemory (historyAttributes, shapeOfHistoryAttributes), + OrtValue.CreateTensorValueFromMemory (parentOf, shapeOfParentOf) + let statePosition_stateToVertex, statePosition_vertexToState = - let data_stateToVertex = Array.zeroCreate (2 * gameState.States.Length) - let data_vertexToState = Array.zeroCreate (2 * gameState.States.Length) - let shape = [|2L; gameState.States.Length|] + let data_stateToVertex = + Array.zeroCreate (2 * gameState.States.Length) + let data_vertexToState = + Array.zeroCreate (2 * gameState.States.Length) + let shape = + [| 2L ; gameState.States.Length |] let mutable firstFreePosition = 0 gameState.GraphVertices - |> Array.iter ( - fun v -> - v.States - |> Array.iteri (fun i stateId -> - let j = firstFreePosition + i - let stateIndex = int64 stateIds[stateId] - let vertexIndex = int64 verticesIds[v.Id] - data_stateToVertex[j] <- stateIndex - data_stateToVertex[stateIds.Count + j] <- vertexIndex - - data_vertexToState[j] <- vertexIndex - data_vertexToState[stateIds.Count + j] <- stateIndex - ) - firstFreePosition <- firstFreePosition + v.States.Length + |> Array.iter (fun v -> + v.States + |> Array.iteri (fun i stateId -> + let j = firstFreePosition + i + let stateIndex = int64 stateIds[stateId] + let vertexIndex = int64 verticesIds[v.Id] + data_stateToVertex[j] <- stateIndex + data_stateToVertex[stateIds.Count + j] <- vertexIndex + + data_vertexToState[j] <- vertexIndex + data_vertexToState[stateIds.Count + j] <- stateIndex ) - OrtValue.CreateTensorValueFromMemory(data_stateToVertex, shape) - ,OrtValue.CreateTensorValueFromMemory(data_vertexToState, shape) - + firstFreePosition <- firstFreePosition + v.States.Length + ) + OrtValue.CreateTensorValueFromMemory (data_stateToVertex, shape), + OrtValue.CreateTensorValueFromMemory (data_vertexToState, shape) + res.Add ("game_vertex", gameVertices) - res.Add ("state_vertex", states) - + res.Add ("state_vertex", states) + res.Add ("gamevertex_to_gamevertex_index", vertexToVertexEdgesIndex) res.Add ("gamevertex_to_gamevertex_type", vertexToVertexEdgesAttributes) - + res.Add ("gamevertex_history_statevertex_index", historyEdgesIndex_vertexToState) res.Add ("gamevertex_history_statevertex_attrs", historyEdgesAttributes) - + res.Add ("gamevertex_in_statevertex", statePosition_vertexToState) res.Add ("statevertex_parentof_statevertex", parentOfEdges) - + res - - let output = session.Run(runOptions, networkInput, session.OutputNames) - let weighedStates = output[0].GetTensorDataAsSpan().ToArray() + + let output = + session.Run (runOptions, networkInput, session.OutputNames) + let weighedStates = + output[0].GetTensorDataAsSpan().ToArray () let id = - weighedStates - |> Array.mapi (fun i v -> i,v) - |> Array.maxBy snd - |> fst - stateIds - |> Seq.find (fun kvp -> kvp.Value = id) - |> fun x -> x.Key - - Oracle(predict,feedback) + weighedStates |> Array.mapi (fun i v -> i, v) |> Array.maxBy snd |> fst + stateIds |> Seq.find (fun kvp -> kvp.Value = id) |> (fun x -> x.Key) + + Oracle (predict, feedback) + + AISearcher (createOracle pathToONNX, None) - AISearcher(createOracle pathToONNX, None) - interface IForwardSearcher with override x.Init states = init states - override x.Pick() = pick (always true) + override x.Pick () = pick (always true) override x.Pick selector = pick selector override x.Update (parent, newStates) = update (parent, newStates) - override x.States() = availableStates - override x.Reset() = reset() + override x.States () = availableStates + override x.Reset () = reset () override x.Remove cilState = remove cilState - override x.StatesCount with get() = availableStates.Count + override x.StatesCount = availableStates.Count diff --git a/VSharp.Explorer/Explorer.fs b/VSharp.Explorer/Explorer.fs index c1ddc51de..bff57569f 100644 --- a/VSharp.Explorer/Explorer.fs +++ b/VSharp.Explorer/Explorer.fs @@ -17,7 +17,7 @@ open VSharp.Solver open VSharp.IL.Serializer type IReporter = - abstract member ReportFinished: UnitTest -> unit + abstract member ReportFinished : UnitTest -> unit abstract member ReportException : UnitTest -> unit abstract member ReportIIE : InsufficientInformationException -> unit abstract member ReportInternalFail : Method -> Exception -> unit @@ -25,14 +25,17 @@ type IReporter = type EntryPointConfiguration(mainArguments : string[]) = - member x.Args with get() = - if mainArguments = null then None - else Some mainArguments + member x.Args = + if mainArguments = null then + None + else + Some mainArguments -type WebConfiguration(mainArguments : string[], environmentName : string, contentRootPath : DirectoryInfo, applicationName : string) = +type WebConfiguration + (mainArguments : string[], environmentName : string, contentRootPath : DirectoryInfo, applicationName : string) = inherit EntryPointConfiguration(mainArguments) - member internal x.ToWebConfig() = + member internal x.ToWebConfig () = { environmentName = environmentName contentRootPath = contentRootPath @@ -40,48 +43,62 @@ type WebConfiguration(mainArguments : string[], environmentName : string, conten } type private IExplorer = - abstract member Reset: seq -> unit - abstract member StartExploration: (Method * state) list -> (Method * EntryPointConfiguration * state) list -> Task + abstract member Reset : seq -> unit + abstract member StartExploration : (Method * state) list -> (Method * EntryPointConfiguration * state) list -> Task -type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVMStatistics, reporter: IReporter) = - let options = explorationOptions.svmOptions +type private SVMExplorer(explorationOptions : ExplorationOptions, statistics : SVMStatistics, reporter : IReporter) = + let options = explorationOptions.svmOptions let folderToStoreSerializationResult = match options.aiAgentTrainingOptions with | None -> "" - | Some options -> getFolderToStoreSerializationResult (Path.GetDirectoryName explorationOptions.outputDirectory.FullName) options.mapName - let hasTimeout = explorationOptions.timeout.TotalMilliseconds > 0 + | Some options -> + getFolderToStoreSerializationResult + (Path.GetDirectoryName explorationOptions.outputDirectory.FullName) + options.mapName + let hasTimeout = + explorationOptions.timeout.TotalMilliseconds > 0 let solverTimeout = - if options.solverTimeout > 0 then options.solverTimeout * 1000 + if options.solverTimeout > 0 then + options.solverTimeout * 1000 // Setting timeout / 2 as solver's timeout doesn't guarantee that SILI // stops exactly in timeout. To guarantee that we need to pass timeout // based on remaining time to solver dynamically. - elif hasTimeout then int explorationOptions.timeout.TotalMilliseconds / 2 - else -1 + elif hasTimeout then + int explorationOptions.timeout.TotalMilliseconds / 2 + else + -1 let branchReleaseTimeout = - let doubleTimeout = double explorationOptions.timeout.TotalMilliseconds - if not hasTimeout then Double.PositiveInfinity - elif not options.releaseBranches then doubleTimeout - else doubleTimeout * 80.0 / 100.0 + let doubleTimeout = + double explorationOptions.timeout.TotalMilliseconds + if not hasTimeout then + Double.PositiveInfinity + elif not options.releaseBranches then + doubleTimeout + else + doubleTimeout * 80.0 / 100.0 let hasStepsLimit = options.stepsLimit > 0u do - API.ConfigureSolver(SolverPool.mkSolver(solverTimeout)) - VSharp.System.SetUp.ConfigureInternalCalls() - API.ConfigureChars(options.prettyChars) + API.ConfigureSolver (SolverPool.mkSolver (solverTimeout)) + VSharp.System.SetUp.ConfigureInternalCalls () + API.ConfigureChars (options.prettyChars) let mutable branchesReleased = false let mutable isStopped = false - let mutable isCoverageAchieved : unit -> bool = always false + let mutable isCoverageAchieved : unit -> bool = + always false - let emptyState = Memory.EmptyIsolatedState() - let interpreter = ILInterpreter() + let emptyState = + Memory.EmptyIsolatedState () + let interpreter = ILInterpreter () do if options.visualize then - DotVisualizer explorationOptions.outputDirectory :> IVisualizer |> Application.setVisualizer + DotVisualizer explorationOptions.outputDirectory :> IVisualizer + |> Application.setVisualizer SetMaxBuferSize options.maxBufferSize TestGenerator.setMaxBufferSize options.maxBufferSize @@ -94,53 +111,72 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM | _ -> false let rec mkForwardSearcher mode = - let getRandomSeedOption() = if options.randomSeed < 0 then None else Some options.randomSeed + let getRandomSeedOption () = + if options.randomSeed < 0 then + None + else + Some options.randomSeed match mode with | AIMode -> match options.aiAgentTrainingOptions with | Some aiOptions -> - match aiOptions.oracle with - | Some oracle -> AISearcher(oracle, options.aiAgentTrainingOptions) :> IForwardSearcher - | None -> failwith "Empty oracle for AI searcher." + match aiOptions.oracle with + | Some oracle -> AISearcher (oracle, options.aiAgentTrainingOptions) :> IForwardSearcher + | None -> failwith "Empty oracle for AI searcher." | None -> match options.pathToModel with | Some s -> AISearcher s | None -> failwith "Empty model for AI searcher." - | BFSMode -> BFSSearcher() :> IForwardSearcher - | DFSMode -> DFSSearcher() :> IForwardSearcher + | BFSMode -> BFSSearcher () :> IForwardSearcher + | DFSMode -> DFSSearcher () :> IForwardSearcher | ShortestDistanceBasedMode -> ShortestDistanceBasedSearcher statistics :> IForwardSearcher - | RandomShortestDistanceBasedMode -> RandomShortestDistanceBasedSearcher(statistics, getRandomSeedOption()) :> IForwardSearcher + | RandomShortestDistanceBasedMode -> + RandomShortestDistanceBasedSearcher (statistics, getRandomSeedOption ()) :> IForwardSearcher | ContributedCoverageMode -> DFSSortedByContributedCoverageSearcher statistics :> IForwardSearcher - | ExecutionTreeMode -> ExecutionTreeSearcher(getRandomSeedOption()) + | ExecutionTreeMode -> ExecutionTreeSearcher (getRandomSeedOption ()) | FairMode baseMode -> - FairSearcher((fun _ -> mkForwardSearcher baseMode), uint branchReleaseTimeout, statistics) :> IForwardSearcher - | InterleavedMode(base1, stepCount1, base2, stepCount2) -> - InterleavedSearcher([mkForwardSearcher base1, stepCount1; mkForwardSearcher base2, stepCount2]) :> IForwardSearcher + FairSearcher ((fun _ -> mkForwardSearcher baseMode), uint branchReleaseTimeout, statistics) + :> IForwardSearcher + | InterleavedMode (base1, stepCount1, base2, stepCount2) -> + InterleavedSearcher ( + [ + mkForwardSearcher base1, stepCount1 + mkForwardSearcher base2, stepCount2 + ] + ) + :> IForwardSearcher let mutable searcher : IBidirectionalSearcher = match options.explorationMode with - | TestCoverageMode(_, searchMode) -> + | TestCoverageMode (_, searchMode) -> let baseSearcher = if options.recThreshold > 0u then - GuidedSearcher(mkForwardSearcher searchMode, RecursionBasedTargetManager(statistics, options.recThreshold)) :> IForwardSearcher + GuidedSearcher ( + mkForwardSearcher searchMode, + RecursionBasedTargetManager (statistics, options.recThreshold) + ) + :> IForwardSearcher else mkForwardSearcher searchMode - BidirectionalSearcher(baseSearcher, BackwardSearcher(), DummyTargetedSearcher.DummyTargetedSearcher()) :> IBidirectionalSearcher - | StackTraceReproductionMode _ -> __notImplemented__() + BidirectionalSearcher (baseSearcher, BackwardSearcher (), DummyTargetedSearcher.DummyTargetedSearcher ()) + :> IBidirectionalSearcher + | StackTraceReproductionMode _ -> __notImplemented__ () - let releaseBranches() = + let releaseBranches () = if not branchesReleased then branchesReleased <- true - statistics.OnBranchesReleased() - ReleaseBranches() - let dfsSearcher = DFSSortedByContributedCoverageSearcher statistics :> IForwardSearcher - let bidirectionalSearcher = OnlyForwardSearcher(dfsSearcher) - dfsSearcher.Init <| searcher.States() + statistics.OnBranchesReleased () + ReleaseBranches () + let dfsSearcher = + DFSSortedByContributedCoverageSearcher statistics :> IForwardSearcher + let bidirectionalSearcher = + OnlyForwardSearcher (dfsSearcher) + dfsSearcher.Init <| searcher.States () searcher <- bidirectionalSearcher let reportStateIncomplete (state : cilState) = searcher.Remove state - statistics.IncompleteStates.Add(state) + statistics.IncompleteStates.Add (state) Application.terminateState state reporter.ReportIIE state.iie.Value @@ -148,31 +184,35 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM let reportState (suite : testSuite) (cilState : cilState) = try - let isNewHistory() = - let methodHistory = Set.filter (fun h -> h.method.InCoverageZone) cilState.history + let isNewHistory () = + let methodHistory = + Set.filter (fun h -> h.method.InCoverageZone) cilState.history Set.isEmpty methodHistory || Set.exists (not << statistics.IsBasicBlockCoveredByTest) methodHistory let isError = suite.IsErrorSuite let isNewTest = match suite with - | Test -> isNewHistory() - | Error(msg, isFatal) -> statistics.IsNewError cilState msg isFatal + | Test -> isNewHistory () + | Error (msg, isFatal) -> statistics.IsNewError cilState msg isFatal if isNewTest then let state = cilState.state - let callStackSize = Memory.CallStackSize state + let callStackSize = + Memory.CallStackSize state let entryMethod = cilState.EntryMethod - let hasException = cilState.IsUnhandledException + let hasException = + cilState.IsUnhandledException if isError && not hasException then if entryMethod.HasParameterOnStack then Memory.ForcePopFrames (callStackSize - 2) state - else Memory.ForcePopFrames (callStackSize - 1) state + else + Memory.ForcePopFrames (callStackSize - 1) state match TestGenerator.state2test suite entryMethod state with | Some test -> - statistics.TrackFinished(cilState, isError) + statistics.TrackFinished (cilState, isError) match suite with | Test -> reporter.ReportFinished test | Error _ -> reporter.ReportException test - if isCoverageAchieved() then + if isCoverageAchieved () then isStopped <- true | None -> () with :? InsufficientInformationException as e -> @@ -187,16 +227,15 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM reportStateIncomplete state | _ -> searcher.Remove state - statistics.InternalFails.Add(e) + statistics.InternalFails.Add (e) Application.terminateState state reporter.ReportInternalFail state.EntryMethod e let reportInternalFail (method : Method) (e : Exception) = match e with - | :? InsufficientInformationException as e -> - reportIncomplete e + | :? InsufficientInformationException as e -> reportIncomplete e | _ -> - statistics.InternalFails.Add(e) + statistics.InternalFails.Add (e) reporter.ReportInternalFail method e let reportFinished (state : cilState) = @@ -209,16 +248,23 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM if not <| String.IsNullOrWhiteSpace errorMessage then Logger.info $"Error in {state.EntryMethod.FullName}: {errorMessage}" Application.terminateState state - let testSuite = Error(errorMessage, isFatal) + let testSuite = + Error (errorMessage, isFatal) reportState testSuite state let reportError = wrapOnError false let reportFatalError = wrapOnError true let reportCrash = reporter.ReportCrash - let isTimeoutReached() = hasTimeout && statistics.CurrentExplorationTime.TotalMilliseconds >= explorationOptions.timeout.TotalMilliseconds - let shouldReleaseBranches() = options.releaseBranches && statistics.CurrentExplorationTime.TotalMilliseconds >= branchReleaseTimeout - let isStepsLimitReached() = hasStepsLimit && statistics.StepsCount >= options.stepsLimit + let isTimeoutReached () = + hasTimeout + && statistics.CurrentExplorationTime.TotalMilliseconds + >= explorationOptions.timeout.TotalMilliseconds + let shouldReleaseBranches () = + options.releaseBranches + && statistics.CurrentExplorationTime.TotalMilliseconds >= branchReleaseTimeout + let isStepsLimitReached () = + hasStepsLimit && statistics.StepsCount >= options.stepsLimit static member private AllocateByRefParameters initialState (method : Method) = let allocateIfByRef (pi : ParameterInfo) = @@ -226,9 +272,10 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM if parameterType.IsByRef then if Memory.CallStackSize initialState = 0 then Memory.NewStackFrame initialState None [] - let typ = parameterType.GetElementType() + let typ = parameterType.GetElementType () let position = pi.Position + 1 - let stackRef = Memory.AllocateTemporaryLocalVariableOfType initialState pi.Name position typ + let stackRef = + Memory.AllocateTemporaryLocalVariableOfType initialState pi.Name position typ Some stackRef else None @@ -238,63 +285,78 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM try initialState.model <- Memory.EmptyModel method let declaringType = method.DeclaringType - let cilState = cilState.CreateInitial method initialState + let cilState = + cilState.CreateInitial method initialState let this = if method.HasThis then if Types.IsValueType declaringType then Memory.NewStackFrame initialState None [] - Memory.AllocateTemporaryLocalVariableOfType initialState "this" 0 declaringType |> Some + Memory.AllocateTemporaryLocalVariableOfType initialState "this" 0 declaringType + |> Some else - let this = Memory.MakeSymbolicThis initialState method + let this = + Memory.MakeSymbolicThis initialState method !!(IsNullReference this) |> AddConstraint initialState Some this - else None - let parameters = SVMExplorer.AllocateByRefParameters initialState method + else + None + let parameters = + SVMExplorer.AllocateByRefParameters initialState method Memory.InitFunctionFrame initialState method this (Some parameters) match this with | Some this -> SolveThisType initialState this | _ -> () - let cilStates = ILInterpreter.CheckDisallowNullAttribute method None cilState false id - assert(List.length cilStates = 1) + let cilStates = + ILInterpreter.CheckDisallowNullAttribute method None cilState false id + assert (List.length cilStates = 1) if not method.IsStaticConstructor then let cilState = List.head cilStates interpreter.InitializeStatics cilState declaringType List.singleton else Memory.MarkTypeInitialized initialState declaringType cilStates - with - | e -> + with e -> reportInternalFail method e [] - member private x.FormEntryPointInitialStates (method : Method, config : EntryPointConfiguration, initialState : state) : cilState list = + member private x.FormEntryPointInitialStates + (method : Method, config : EntryPointConfiguration, initialState : state) + : cilState list = try assert method.IsStatic let optionArgs = config.Args let parameters = method.Parameters - let hasParameters = Array.length parameters > 0 - let state = { initialState with complete = not hasParameters || Option.isSome optionArgs } + let hasParameters = + Array.length parameters > 0 + let state = + { initialState with + complete = not hasParameters || Option.isSome optionArgs + } state.model <- Memory.EmptyModel method match optionArgs with | Some args -> let stringType = typeof let argsNumber = MakeNumber args.Length - let argsRef = Memory.AllocateConcreteVectorArray state argsNumber stringType args - let args = Some (List.singleton (Some argsRef)) + let argsRef = + Memory.AllocateConcreteVectorArray state argsNumber stringType args + let args = + Some (List.singleton (Some argsRef)) Memory.InitFunctionFrame state method None args | None when hasParameters -> Memory.InitFunctionFrame state method None None // NOTE: if args are symbolic, constraint 'args != null' is added - assert(Array.length parameters = 1) + assert (Array.length parameters = 1) let argsParameter = Array.head parameters - let argsParameterTerm = Memory.ReadArgument state argsParameter + let argsParameterTerm = + Memory.ReadArgument state argsParameter AddConstraint state (!!(IsNullReference argsParameterTerm)) // Filling model with default args to match PC let modelState = match state.model with | StateModel modelState -> modelState - | _ -> __unreachable__() - let argsForModel = Memory.AllocateVectorArray modelState (MakeNumber 0) typeof + | _ -> __unreachable__ () + let argsForModel = + Memory.AllocateVectorArray modelState (MakeNumber 0) typeof Memory.WriteStackLocation modelState (ParameterKey argsParameter) argsForModel | None -> let args = Some List.empty @@ -303,12 +365,11 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM let initialState = match config with | :? WebConfiguration as config -> - let webConfig = config.ToWebConfig() + let webConfig = config.ToWebConfig () cilState.CreateWebInitial method state webConfig | _ -> cilState.CreateInitial method state - [initialState] - with - | e -> + [ initialState ] + with e -> reportInternalFail method e [] @@ -317,31 +378,34 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM let ip = s.CurrentIp let stackSize = s.StackSize // TODO: update pobs when visiting new methods; use coverageZone - let goodStates, iieStates, errors = interpreter.ExecuteOneInstruction s + let goodStates, iieStates, errors = + interpreter.ExecuteOneInstruction s for s in goodStates @ iieStates @ errors do if not s.HasRuntimeExceptionOrError then statistics.TrackStepForward s ip stackSize - let goodStates, toReportFinished = goodStates |> List.partition (fun s -> s.IsExecutable || s.IsIsolated) + let goodStates, toReportFinished = + goodStates |> List.partition (fun s -> s.IsExecutable || s.IsIsolated) toReportFinished |> List.iter reportFinished - let errors, _ = errors |> List.partition (fun s -> not s.HasReportedError) - let errors, toReportExceptions = errors |> List.partition (fun s -> s.IsIsolated || not s.IsStoppedByException) - let runtimeExceptions, userExceptions = toReportExceptions |> List.partition (fun s -> s.HasRuntimeExceptionOrError) + let errors, _ = + errors |> List.partition (fun s -> not s.HasReportedError) + let errors, toReportExceptions = + errors |> List.partition (fun s -> s.IsIsolated || not s.IsStoppedByException) + let runtimeExceptions, userExceptions = + toReportExceptions |> List.partition (fun s -> s.HasRuntimeExceptionOrError) runtimeExceptions |> List.iter (fun state -> reportError state null) userExceptions |> List.iter reportFinished - let iieStates, toReportIIE = iieStates |> List.partition (fun s -> s.IsIsolated) + let iieStates, toReportIIE = + iieStates |> List.partition (fun s -> s.IsIsolated) toReportIIE |> List.iter reportStateIncomplete let mutable sIsStopped = false let newStates = match goodStates, iieStates, errors with - | s'::goodStates, _, _ when LanguagePrimitives.PhysicalEquality s s' -> - goodStates @ iieStates @ errors - | _, s'::iieStates, _ when LanguagePrimitives.PhysicalEquality s s' -> - goodStates @ iieStates @ errors - | _, _, s'::errors when LanguagePrimitives.PhysicalEquality s s' -> - goodStates @ iieStates @ errors + | s' :: goodStates, _, _ when LanguagePrimitives.PhysicalEquality s s' -> goodStates @ iieStates @ errors + | _, s' :: iieStates, _ when LanguagePrimitives.PhysicalEquality s s' -> goodStates @ iieStates @ errors + | _, _, s' :: errors when LanguagePrimitives.PhysicalEquality s s' -> goodStates @ iieStates @ errors | _ -> sIsStopped <- true - goodStates @ iieStates @ errors + goodStates @ iieStates @ errors s.children <- s.children @ newStates Application.moveState loc s (Seq.cast<_> newStates) @@ -351,7 +415,7 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM searcher.Remove s member private x.Backward p' (s' : cilState) = - assert(s'.CurrentLoc = p'.loc) + assert (s'.CurrentLoc = p'.loc) let sLvl = s'.Level if p'.lvl >= sLvl then let lvl = p'.lvl - sLvl @@ -360,191 +424,227 @@ type private SVMExplorer(explorationOptions: ExplorationOptions, statistics: SVM | true when not s'.IsIsolated -> searcher.Answer p' (Witnessed s') | true -> statistics.TrackStepBackward p' s' - let p = {loc = s'.StartingLoc; lvl = lvl; pc = pc} + let p = + { + loc = s'.StartingLoc + lvl = lvl + pc = pc + } Logger.trace $"Backward:\nWas: {p'}\nNow: {p}\n\n" Application.addGoal p.loc searcher.UpdatePobs p' p - | false -> - Logger.trace "UNSAT for pob = %O and s'.PC = %s" p' (API.Print.PrintPC s'.state.pc) + | false -> Logger.trace "UNSAT for pob = %O and s'.PC = %s" p' (API.Print.PrintPC s'.state.pc) + + member private x.BidirectionalSymbolicExecution () = - member private x.BidirectionalSymbolicExecution() = - let mutable action = Stop - - let pick() = - match searcher.Pick() with + + let pick () = + match searcher.Pick () with | Stop -> false - | a -> action <- a; true + | a -> + action <- a + true (* TODO: checking for timeout here is not fine-grained enough (that is, we can work significantly beyond the timeout, but we'll live with it for now. *) - while not isStopped && not <| isStepsLimitReached() && not <| isTimeoutReached() && pick() do - if shouldReleaseBranches() then - releaseBranches() + while not isStopped + && not <| isStepsLimitReached () + && not <| isTimeoutReached () + && pick () do + if shouldReleaseBranches () then + releaseBranches () match action with | GoFront s -> try - if options.aiAgentTrainingOptions.IsSome && options.aiAgentTrainingOptions.Value.serializeSteps + if + options.aiAgentTrainingOptions.IsSome + && options.aiAgentTrainingOptions.Value.serializeSteps then - dumpGameState (Path.Combine(folderToStoreSerializationResult, string firstFreeEpisodeNumber)) s.internalId + dumpGameState + (Path.Combine (folderToStoreSerializationResult, string firstFreeEpisodeNumber)) + s.internalId firstFreeEpisodeNumber <- firstFreeEpisodeNumber + 1 - x.Forward(s) - with - | e -> reportStateInternalFail s e - | GoBack(s, p) -> + x.Forward (s) + with e -> + reportStateInternalFail s e + | GoBack (s, p) -> try x.Backward p s - with - | e -> reportStateInternalFail s e - | Stop -> __unreachable__() + with e -> + reportStateInternalFail s e + | Stop -> __unreachable__ () member private x.AnswerPobs initialStates = - statistics.ExplorationStarted() + statistics.ExplorationStarted () // For backward compatibility. TODO: remove main pobs at all let mainPobs = [] Application.spawnStates (Seq.cast<_> initialStates) mainPobs |> Seq.map (fun pob -> pob.loc) |> Seq.toArray |> Application.addGoals searcher.Init initialStates mainPobs - initialStates |> Seq.filter (fun s -> s.IsIIEState) |> Seq.iter reportStateIncomplete - x.BidirectionalSymbolicExecution() - searcher.Statuses() |> Seq.iter (fun (pob, status) -> + initialStates + |> Seq.filter (fun s -> s.IsIIEState) + |> Seq.iter reportStateIncomplete + x.BidirectionalSymbolicExecution () + searcher.Statuses () + |> Seq.iter (fun (pob, status) -> match status with - | pobStatus.Unknown -> - Logger.warning $"Unknown status for pob at {pob.loc}" - | _ -> ()) + | pobStatus.Unknown -> Logger.warning $"Unknown status for pob at {pob.loc}" + | _ -> () + ) interface IExplorer with member x.Reset entryMethods = - HashMap.clear() - API.Reset() - SolverPool.reset() - searcher.Reset() + HashMap.clear () + API.Reset () + SolverPool.reset () + searcher.Reset () isStopped <- false branchesReleased <- false SolverInteraction.setOnSolverStarted statistics.SolverStarted SolverInteraction.setOnSolverStopped statistics.SolverStopped - AcquireBranches() + AcquireBranches () isCoverageAchieved <- always false match options.explorationMode with | TestCoverageMode _ -> if options.stopOnCoverageAchieved > 0 then - let checkCoverage() = - let cov = statistics.GetCurrentCoverage entryMethods + let checkCoverage () = + let cov = + statistics.GetCurrentCoverage entryMethods cov >= options.stopOnCoverageAchieved isCoverageAchieved <- checkCoverage - | StackTraceReproductionMode _ -> __notImplemented__() + | StackTraceReproductionMode _ -> __notImplemented__ () member x.StartExploration isolated entryPoints = task { try try interpreter.ConfigureErrorReporter reportError reportFatalError - let isolatedInitialStates = isolated |> List.collect x.FormIsolatedInitialStates - let entryPointsInitialStates = entryPoints |> List.collect x.FormEntryPointInitialStates + let isolatedInitialStates = + isolated |> List.collect x.FormIsolatedInitialStates + let entryPointsInitialStates = + entryPoints |> List.collect x.FormEntryPointInitialStates let iieStates, initialStates = isolatedInitialStates @ entryPointsInitialStates |> List.partition (fun state -> state.IsIIEState) iieStates |> List.iter reportStateIncomplete - statistics.SetStatesGetter(fun () -> searcher.States()) - statistics.SetStatesCountGetter(fun () -> searcher.StatesCount) + statistics.SetStatesGetter (fun () -> searcher.States ()) + statistics.SetStatesCountGetter (fun () -> searcher.StatesCount) if not initialStates.IsEmpty then x.AnswerPobs initialStates - with e -> reportCrash e + with e -> + reportCrash e finally try - statistics.ExplorationFinished() - API.Restore() - searcher.Reset() - with e -> reportCrash e + statistics.ExplorationFinished () + API.Restore () + searcher.Reset () + with e -> + reportCrash e } - member private x.Stop() = isStopped <- true + member private x.Stop () = isStopped <- true -type private FuzzerExplorer(explorationOptions: ExplorationOptions, statistics: SVMStatistics) = +type private FuzzerExplorer(explorationOptions : ExplorationOptions, statistics : SVMStatistics) = interface IExplorer with member x.Reset _ = () member x.StartExploration isolated _ = - let saveStatistic = statistics.SetBasicBlocksAsCoveredByTest - let outputDir = explorationOptions.outputDirectory.FullName - let cancellationTokenSource = new CancellationTokenSource() - cancellationTokenSource.CancelAfter(explorationOptions.timeout) - let methodsBase = isolated |> List.map (fun (m, _) -> (m :> IMethod).MethodBase) + let saveStatistic = + statistics.SetBasicBlocksAsCoveredByTest + let outputDir = + explorationOptions.outputDirectory.FullName + let cancellationTokenSource = + new CancellationTokenSource () + cancellationTokenSource.CancelAfter (explorationOptions.timeout) + let methodsBase = + isolated |> List.map (fun (m, _) -> (m :> IMethod).MethodBase) task { try - let targetAssemblyPath = (Seq.head methodsBase).Module.Assembly.Location + let targetAssemblyPath = + (Seq.head methodsBase).Module.Assembly.Location let onCancelled () = Logger.warning "Fuzzer canceled" - let interactor = Fuzzer.Interactor( - targetAssemblyPath, - methodsBase, - cancellationTokenSource.Token, - outputDir, - saveStatistic, - onCancelled - ) + let interactor = + Fuzzer.Interactor ( + targetAssemblyPath, + methodsBase, + cancellationTokenSource.Token, + outputDir, + saveStatistic, + onCancelled + ) do! interactor.StartFuzzing () with e -> Logger.error $"Fuzzer unhandled exception: {e}" raise e } -type public Explorer(options : ExplorationOptions, reporter: IReporter) = +type public Explorer(options : ExplorationOptions, reporter : IReporter) = - let statistics = new SVMStatistics(Seq.empty, true) + let statistics = + new SVMStatistics (Seq.empty, true) let explorers = let createFuzzer () = - FuzzerExplorer(options, statistics) :> IExplorer + FuzzerExplorer (options, statistics) :> IExplorer let createSVM () = - SVMExplorer(options, statistics, reporter) :> IExplorer + SVMExplorer (options, statistics, reporter) :> IExplorer match options.explorationModeOptions with - | Fuzzing _ -> createFuzzer() |> Array.singleton - | SVM _ -> createSVM() |> Array.singleton - | Combined _ -> - [| - createFuzzer() - createSVM() - |] + | Fuzzing _ -> createFuzzer () |> Array.singleton + | SVM _ -> createSVM () |> Array.singleton + | Combined _ -> [| createFuzzer () ; createSVM () |] let inCoverageZone coverageZone (entryMethods : Method list) = match coverageZone with | MethodZone -> fun method -> entryMethods |> List.contains method - | ClassZone -> fun method -> entryMethods |> List.exists (fun m -> method.DeclaringType.TypeHandle = m.DeclaringType.TypeHandle) - | ModuleZone -> fun method -> entryMethods |> List.exists (fun m -> method.Module.ModuleHandle = m.Module.ModuleHandle) + | ClassZone -> + fun method -> + entryMethods + |> List.exists (fun m -> method.DeclaringType.TypeHandle = m.DeclaringType.TypeHandle) + | ModuleZone -> + fun method -> + entryMethods + |> List.exists (fun m -> method.Module.ModuleHandle = m.Module.ModuleHandle) member private x.TrySubstituteTypeParameters (state : state) (methodBase : MethodBase) = - let method = Application.getMethod methodBase - let getConcreteType = function - | ConcreteType t -> Some t - | _ -> None + let method = + Application.getMethod methodBase + let getConcreteType = + function + | ConcreteType t -> Some t + | _ -> None try if method.ContainsGenericParameters then match SolveGenericMethodParameters state.typeStorage method with - | Some(classParams, methodParams) -> - let classParams = classParams |> Array.choose getConcreteType - let methodParams = methodParams |> Array.choose getConcreteType + | Some (classParams, methodParams) -> + let classParams = + classParams |> Array.choose getConcreteType + let methodParams = + methodParams |> Array.choose getConcreteType let declaringType = methodBase.DeclaringType - let isSuitableType() = + let isSuitableType () = not declaringType.IsGenericType || classParams.Length = declaringType.GetGenericArguments().Length - let isSuitableMethod() = + let isSuitableMethod () = methodBase.IsConstructor || not methodBase.IsGenericMethod || methodParams.Length = methodBase.GetGenericArguments().Length - if isSuitableType() && isSuitableMethod() then - let reflectedType = Reflection.concretizeTypeParameters methodBase.ReflectedType classParams - let method = Reflection.concretizeMethodParameters reflectedType methodBase methodParams + if isSuitableType () && isSuitableMethod () then + let reflectedType = + Reflection.concretizeTypeParameters methodBase.ReflectedType classParams + let method = + Reflection.concretizeMethodParameters reflectedType methodBase methodParams Some method else None | _ -> None - else Some methodBase - with - | e -> + else + Some methodBase + with e -> reporter.ReportInternalFail method e None @@ -554,45 +654,50 @@ type public Explorer(options : ExplorationOptions, reporter: IReporter) = for explorer in explorers do explorer.Reset entryMethods - member x.StartExploration (isolated : MethodBase seq) (entryPoints : (MethodBase * EntryPointConfiguration) seq) : unit = + member x.StartExploration + (isolated : MethodBase seq) + (entryPoints : (MethodBase * EntryPointConfiguration) seq) + : unit = try let trySubstituteTypeParameters method = - let emptyState = Memory.EmptyIsolatedState() + let emptyState = + Memory.EmptyIsolatedState () (Option.defaultValue method (x.TrySubstituteTypeParameters emptyState method), emptyState) let isolated = isolated |> Seq.map trySubstituteTypeParameters - |> Seq.map (fun (m, s) -> Application.getMethod m, s) |> Seq.toList + |> Seq.map (fun (m, s) -> Application.getMethod m, s) + |> Seq.toList let entryPoints = entryPoints |> Seq.map (fun (m, a) -> let m, s = trySubstituteTypeParameters m - (Application.getMethod m, a, s)) + (Application.getMethod m, a, s) + ) |> Seq.toList - (List.map fst isolated) - @ (List.map (fun (x, _, _) -> x) entryPoints) - |> x.Reset + (List.map fst isolated) @ (List.map (fun (x, _, _) -> x) entryPoints) |> x.Reset let explorationTasks = - explorers - |> Array.map (fun e -> e.StartExploration isolated entryPoints) + explorers |> Array.map (fun e -> e.StartExploration isolated entryPoints) - let finished = Task.WaitAll(explorationTasks, options.timeout) + let finished = + Task.WaitAll (explorationTasks, options.timeout) - if not finished then Logger.warning "Exploration cancelled" + if not finished then + Logger.warning "Exploration cancelled" for explorationTask in explorationTasks do if explorationTask.IsFaulted then for ex in explorationTask.Exception.InnerExceptions do - reporter.ReportCrash ex + reporter.ReportCrash ex with | :? AggregateException as e -> reporter.ReportCrash e.InnerException | e -> reporter.ReportCrash e - member x.Statistics with get() = statistics + member x.Statistics = statistics interface IDisposable with - member x.Dispose() = (statistics :> IDisposable).Dispose() + member x.Dispose () = (statistics :> IDisposable).Dispose () diff --git a/VSharp.Explorer/Options.fs b/VSharp.Explorer/Options.fs index e78bac048..a573129d0 100644 --- a/VSharp.Explorer/Options.fs +++ b/VSharp.Explorer/Options.fs @@ -24,19 +24,23 @@ type explorationMode = | TestCoverageMode of coverageZone * searchMode | StackTraceReproductionMode of StackTrace -type fuzzerIsolation = - | Process +type fuzzerIsolation = | Process -type FuzzerOptions = { - isolation: fuzzerIsolation - coverageZone: coverageZone -} +type FuzzerOptions = + { + isolation : fuzzerIsolation + coverageZone : coverageZone + } [] type Oracle = - val Predict: GameState -> uint - val Feedback: Feedback -> unit - new (predict, feedback) = {Predict=predict; Feedback = feedback} + val Predict : GameState -> uint + val Feedback : Feedback -> unit + new(predict, feedback) = + { + Predict = predict + Feedback = feedback + } /// /// Options used in AI agent training. @@ -49,41 +53,43 @@ type Oracle = /// Name of map to play. type AIAgentTrainingOptions = { - stepsToSwitchToAI: uint - stepsToPlay: uint - defaultSearchStrategy: searchMode - serializeSteps: bool - mapName: string - oracle: Option + stepsToSwitchToAI : uint + stepsToPlay : uint + defaultSearchStrategy : searchMode + serializeSteps : bool + mapName : string + oracle : Option + } + +type SVMOptions = + { + explorationMode : explorationMode + recThreshold : uint + solverTimeout : int + visualize : bool + releaseBranches : bool + maxBufferSize : int + prettyChars : bool // If true, 33 <= char <= 126, otherwise any char + checkAttributes : bool + stopOnCoverageAchieved : int + randomSeed : int + stepsLimit : uint + aiAgentTrainingOptions : Option + pathToModel : Option } - -type SVMOptions = { - explorationMode : explorationMode - recThreshold : uint - solverTimeout : int - visualize : bool - releaseBranches : bool - maxBufferSize : int - prettyChars : bool // If true, 33 <= char <= 126, otherwise any char - checkAttributes : bool - stopOnCoverageAchieved : int - randomSeed : int - stepsLimit : uint - aiAgentTrainingOptions: Option - pathToModel: Option -} type explorationModeOptions = | Fuzzing of FuzzerOptions | SVM of SVMOptions | Combined of SVMOptions * FuzzerOptions -type ExplorationOptions = { - timeout : System.TimeSpan - outputDirectory : DirectoryInfo - explorationModeOptions : explorationModeOptions -} -with +type ExplorationOptions = + { + timeout : System.TimeSpan + outputDirectory : DirectoryInfo + explorationModeOptions : explorationModeOptions + } + member this.fuzzerOptions = match this.explorationModeOptions with | Fuzzing x -> x @@ -100,7 +106,7 @@ with match this.explorationModeOptions with | SVM x -> match x.explorationMode with - | TestCoverageMode (coverageZone, _) -> coverageZone + | TestCoverageMode (coverageZone, _) -> coverageZone | StackTraceReproductionMode _ -> failwith "" | Combined (_, x) -> x.coverageZone | Fuzzing x -> x.coverageZone diff --git a/VSharp.ML.GameServer.Runner/Main.fs b/VSharp.ML.GameServer.Runner/Main.fs index 7c4e8a177..3684ab0be 100644 --- a/VSharp.ML.GameServer.Runner/Main.fs +++ b/VSharp.ML.GameServer.Runner/Main.fs @@ -19,18 +19,18 @@ open VSharp.Runner [] type ExplorationResult = - val ActualCoverage: uint - val TestsCount: uint - val ErrorsCount: uint - val StepsCount: uint - new (actualCoverage, testsCount, errorsCount, stepsCount) = + val ActualCoverage : uint + val TestsCount : uint + val ErrorsCount : uint + val StepsCount : uint + new(actualCoverage, testsCount, errorsCount, stepsCount) = { ActualCoverage = actualCoverage TestsCount = testsCount ErrorsCount = errorsCount StepsCount = stepsCount } - + type Mode = | Server = 0 | Generator = 1 @@ -38,154 +38,193 @@ type CliArguments = | [] Port of int | [] DatasetBasePath of string | [] DatasetDescription of string - | [] Mode of Mode + | [] Mode of Mode | [] OutFolder of string | [] StepsToSerialize of uint + interface IArgParserTemplate with member s.Usage = match s with | Port _ -> "Port to communicate with game client." - | DatasetBasePath _ -> "Full path to dataset root directory. Dll location is /" + | DatasetBasePath _ -> + "Full path to dataset root directory. Dll location is /" | DatasetDescription _ -> "Full paths to JSON-file with dataset description." - | Mode _ -> "Mode to run application. Server --- to train network, Generator --- to generate data for training." + | Mode _ -> + "Mode to run application. Server --- to train network, Generator --- to generate data for training." | OutFolder _ -> "Folder to store generated data." | StepsToSerialize _ -> "Maximal number of steps for each method to serialize." - + let mutable inTrainMode = true -let explore (gameMap:GameMap) options = - let assembly = RunnerProgram.TryLoadAssembly <| FileInfo gameMap.AssemblyFullName - let method = RunnerProgram.ResolveMethod(assembly, gameMap.NameOfObjectToCover) - let statistics = TestGenerator.Cover(method, options) - let actualCoverage = - try +let explore (gameMap : GameMap) options = + let assembly = + RunnerProgram.TryLoadAssembly <| FileInfo gameMap.AssemblyFullName + let method = + RunnerProgram.ResolveMethod (assembly, gameMap.NameOfObjectToCover) + let statistics = + TestGenerator.Cover (method, options) + let actualCoverage = + try let testsDir = statistics.OutputDir let _expectedCoverage = 100 - let exploredMethodInfo = AssemblyManager.NormalizeMethod method - let status,actualCoverage,message = VSharp.Test.TestResultChecker.Check(testsDir, exploredMethodInfo :?> MethodInfo, _expectedCoverage) + let exploredMethodInfo = + AssemblyManager.NormalizeMethod method + let status, actualCoverage, message = + VSharp.Test.TestResultChecker.Check (testsDir, exploredMethodInfo :?> MethodInfo, _expectedCoverage) printfn $"Actual coverage for {gameMap.MapName}: {actualCoverage}" - if actualCoverage < 0 then 0u else uint actualCoverage * 1u - with - e -> + if actualCoverage < 0 then + 0u + else + uint actualCoverage * 1u + with e -> printfn $"Coverage checking problem:{e.Message} \n {e.StackTrace}" 0u - ExplorationResult(actualCoverage, statistics.TestsCount * 1u, statistics.ErrorsCount *1u, statistics.StepsCount * 1u) + ExplorationResult ( + actualCoverage, + statistics.TestsCount * 1u, + statistics.ErrorsCount * 1u, + statistics.StepsCount * 1u + ) -let loadGameMaps (datasetDescriptionFilePath:string) = - let jsonString = File.ReadAllText datasetDescriptionFilePath - let maps = ResizeArray() - for map in System.Text.Json.JsonSerializer.Deserialize jsonString do - maps.Add map +let loadGameMaps (datasetDescriptionFilePath : string) = + let jsonString = + File.ReadAllText datasetDescriptionFilePath + let maps = ResizeArray () + for map in System.Text.Json.JsonSerializer.Deserialize jsonString do + maps.Add map maps -let ws port outputDirectory (webSocket : WebSocket) (context: HttpContext) = - let mutable loop = true - - socket { - - let sendResponse (message:OutgoingMessage) = - let byteResponse = - serializeOutgoingMessage message - |> System.Text.Encoding.UTF8.GetBytes - |> ByteSegment - webSocket.send Text byteResponse true - - let oracle = - let feedback = - fun (feedback: Feedback) -> - let res = - socket { - let message = - match feedback with - | Feedback.ServerError s -> OutgoingMessage.ServerError s - | Feedback.MoveReward reward -> OutgoingMessage.MoveReward reward - | Feedback.IncorrectPredictedStateId i -> OutgoingMessage.IncorrectPredictedStateId i - do! sendResponse message - } - match Async.RunSynchronously res with - | Choice1Of2 () -> () - | Choice2Of2 error -> failwithf $"Error: %A{error}" - - let predict = - let mutable cnt = 0u - fun (gameState:GameState) -> - let toDot drawHistory = - let file = Path.Join ("dot",$"{cnt}.dot") - gameState.ToDot file drawHistory - cnt <- cnt + 1u - //toDot false - let res = - socket { - do! sendResponse (ReadyForNextStep gameState) - let! msg = webSocket.read() - let res = - match msg with - | (Text, data, true) -> - let msg = deserializeInputMessage data +let ws port outputDirectory (webSocket : WebSocket) (context : HttpContext) = + let mutable loop = true + + socket { + + let sendResponse (message : OutgoingMessage) = + let byteResponse = + serializeOutgoingMessage message + |> System.Text.Encoding.UTF8.GetBytes + |> ByteSegment + webSocket.send Text byteResponse true + + let oracle = + let feedback = + fun (feedback : Feedback) -> + let res = + socket { + let message = + match feedback with + | Feedback.ServerError s -> OutgoingMessage.ServerError s + | Feedback.MoveReward reward -> OutgoingMessage.MoveReward reward + | Feedback.IncorrectPredictedStateId i -> OutgoingMessage.IncorrectPredictedStateId i + do! sendResponse message + } + match Async.RunSynchronously res with + | Choice1Of2 () -> () + | Choice2Of2 error -> failwithf $"Error: %A{error}" + + let predict = + let mutable cnt = 0u + fun (gameState : GameState) -> + let toDot drawHistory = + let file = Path.Join ("dot", $"{cnt}.dot") + gameState.ToDot file drawHistory + cnt <- cnt + 1u + //toDot false + let res = + socket { + do! sendResponse (ReadyForNextStep gameState) + let! msg = webSocket.read () + let res = match msg with - | Step stepParams -> (stepParams.StateId) + | (Text, data, true) -> + let msg = deserializeInputMessage data + match msg with + | Step stepParams -> (stepParams.StateId) + | _ -> failwithf $"Unexpected message: %A{msg}" | _ -> failwithf $"Unexpected message: %A{msg}" - | _ -> failwithf $"Unexpected message: %A{msg}" - return res - } - match Async.RunSynchronously res with - | Choice1Of2 i -> i - | Choice2Of2 error -> failwithf $"Error: %A{error}" - - Oracle(predict,feedback) - - while loop do - let! msg = webSocket.read() - match msg with - | (Text, data, true) -> + return res + } + match Async.RunSynchronously res with + | Choice1Of2 i -> i + | Choice2Of2 error -> failwithf $"Error: %A{error}" + + Oracle (predict, feedback) + + while loop do + let! msg = webSocket.read () + match msg with + | (Text, data, true) -> let message = deserializeInputMessage data match message with | ServerStop -> loop <- false | Start gameMap -> printfn $"Start map {gameMap.MapName}, port {port}" let aiTrainingOptions = - { - stepsToSwitchToAI = gameMap.StepsToStart - stepsToPlay = gameMap.StepsToPlay - defaultSearchStrategy = - match gameMap.DefaultSearcher with - | searcher.BFS -> BFSMode - | searcher.DFS -> DFSMode - | x -> failwithf $"Unexpected searcher {x}. Use DFS or BFS for now." - serializeSteps = false - mapName = gameMap.MapName - oracle = Some oracle - } - let options = VSharpOptions(timeout = 15 * 60, outputDirectory = outputDirectory, searchStrategy = SearchStrategy.AI, aiAgentTrainingOptions = aiTrainingOptions, solverTimeout=2) - let explorationResult = explore gameMap options - - Application.reset() - API.Reset() - HashMap.hashMap.Clear() - do! sendResponse (GameOver (explorationResult.ActualCoverage, explorationResult.TestsCount, explorationResult.ErrorsCount)) + { + stepsToSwitchToAI = gameMap.StepsToStart + stepsToPlay = gameMap.StepsToPlay + defaultSearchStrategy = + match gameMap.DefaultSearcher with + | searcher.BFS -> BFSMode + | searcher.DFS -> DFSMode + | x -> failwithf $"Unexpected searcher {x}. Use DFS or BFS for now." + serializeSteps = false + mapName = gameMap.MapName + oracle = Some oracle + } + let options = + VSharpOptions ( + timeout = 15 * 60, + outputDirectory = outputDirectory, + searchStrategy = SearchStrategy.AI, + aiAgentTrainingOptions = aiTrainingOptions, + solverTimeout = 2 + ) + let explorationResult = + explore gameMap options + + Application.reset () + API.Reset () + HashMap.hashMap.Clear () + do! + sendResponse ( + GameOver ( + explorationResult.ActualCoverage, + explorationResult.TestsCount, + explorationResult.ErrorsCount + ) + ) printfn $"Finish map {gameMap.MapName}, port {port}" | x -> failwithf $"Unexpected message: %A{x}" - - | (Close, _, _) -> + + | (Close, _, _) -> let emptyResponse = [||] |> ByteSegment do! webSocket.send Close emptyResponse true loop <- false - | _ -> () + | _ -> () } - + let app port outputDirectory : WebPart = - choose [ - path "/gameServer" >=> handShake (ws port outputDirectory) - ] + choose + [ + path "/gameServer" >=> handShake (ws port outputDirectory) + ] -let generateDataForPretraining outputDirectory datasetBasePath (maps:ResizeArray) stepsToSerialize = +let generateDataForPretraining outputDirectory datasetBasePath (maps : ResizeArray) stepsToSerialize = for map in maps do - if map.StepsToStart = 0u - then + if map.StepsToStart = 0u then printfn $"Generation for {map.MapName} started." - let map = GameMap(map.StepsToPlay, map.StepsToStart, Path.Combine (datasetBasePath, map.AssemblyFullName), map.DefaultSearcher, map.NameOfObjectToCover, map.MapName) + let map = + GameMap ( + map.StepsToPlay, + map.StepsToStart, + Path.Combine (datasetBasePath, map.AssemblyFullName), + map.DefaultSearcher, + map.NameOfObjectToCover, + map.MapName + ) let aiTrainingOptions = { stepsToSwitchToAI = 0u @@ -195,68 +234,89 @@ let generateDataForPretraining outputDirectory datasetBasePath (maps:ResizeArray mapName = map.MapName oracle = None } - - let options = VSharpOptions(timeout = 5 * 60, outputDirectory = outputDirectory, searchStrategy = SearchStrategy.ExecutionTreeContributedCoverage, stepsLimit = stepsToSerialize, solverTimeout=2, aiAgentTrainingOptions = aiTrainingOptions) - let folderForResults = Serializer.getFolderToStoreSerializationResult outputDirectory map.MapName - if Directory.Exists folderForResults - then Directory.Delete(folderForResults, true) - let _ = Directory.CreateDirectory folderForResults - + + let options = + VSharpOptions ( + timeout = 5 * 60, + outputDirectory = outputDirectory, + searchStrategy = SearchStrategy.ExecutionTreeContributedCoverage, + stepsLimit = stepsToSerialize, + solverTimeout = 2, + aiAgentTrainingOptions = aiTrainingOptions + ) + let folderForResults = + Serializer.getFolderToStoreSerializationResult outputDirectory map.MapName + if Directory.Exists folderForResults then + Directory.Delete (folderForResults, true) + let _ = + Directory.CreateDirectory folderForResults + let explorationResult = explore map options - File.WriteAllText(Path.Join(folderForResults, "result"), $"{explorationResult.ActualCoverage} {explorationResult.TestsCount} {explorationResult.StepsCount} {explorationResult.ErrorsCount}") - printfn $"Generation for {map.MapName} finished with coverage {explorationResult.ActualCoverage}, tests {explorationResult.TestsCount}, steps {explorationResult.StepsCount},errors {explorationResult.ErrorsCount}." - Application.reset() - API.Reset() - HashMap.hashMap.Clear() + File.WriteAllText ( + Path.Join (folderForResults, "result"), + $"{explorationResult.ActualCoverage} {explorationResult.TestsCount} {explorationResult.StepsCount} {explorationResult.ErrorsCount}" + ) + printfn + $"Generation for {map.MapName} finished with coverage {explorationResult.ActualCoverage}, tests {explorationResult.TestsCount}, steps {explorationResult.StepsCount},errors {explorationResult.ErrorsCount}." + Application.reset () + API.Reset () + HashMap.hashMap.Clear () [] let main args = - let parser = ArgumentParser.Create(programName = "VSharp.ML.GameServer.Runner.exe") + let parser = + ArgumentParser.Create (programName = "VSharp.ML.GameServer.Runner.exe") let args = parser.Parse args - - let mode = args.GetResult <@Mode@> - + + let mode = args.GetResult <@ Mode @> + let port = - match args.TryGetResult <@Port@> with + match args.TryGetResult <@ Port @> with | Some port -> port | None -> 8100 - - let datasetBasePath = - match args.TryGetResult <@DatasetBasePath@> with + + let datasetBasePath = + match args.TryGetResult <@ DatasetBasePath @> with | Some path -> path | None -> "" - - let datasetDescription = - match args.TryGetResult <@DatasetDescription@> with + + let datasetDescription = + match args.TryGetResult <@ DatasetDescription @> with | Some path -> path | None -> "" let stepsToSerialize = - match args.TryGetResult <@StepsToSerialize@> with + match args.TryGetResult <@ StepsToSerialize @> with | Some steps -> steps | None -> 500u - + let outputDirectory = - Path.Combine(Directory.GetCurrentDirectory(), string port) - - if Directory.Exists outputDirectory - then Directory.Delete(outputDirectory,true) - let testsDirInfo = Directory.CreateDirectory outputDirectory - printfn $"outputDir: {outputDirectory}" - + Path.Combine (Directory.GetCurrentDirectory (), string port) + + if Directory.Exists outputDirectory then + Directory.Delete (outputDirectory, true) + let testsDirInfo = + Directory.CreateDirectory outputDirectory + printfn $"outputDir: {outputDirectory}" + match mode with | Mode.Server -> - try - startWebServer {defaultConfig with - logger = Targets.create Verbose [||] - bindings = [HttpBinding.createSimple HTTP "127.0.0.1" port]} (app port outputDirectory) - with - | e -> + try + startWebServer + { defaultConfig with + logger = Targets.create Verbose [||] + bindings = + [ + HttpBinding.createSimple HTTP "127.0.0.1" port + ] + } + (app port outputDirectory) + with e -> printfn $"Failed on port {port}" printfn $"{e.Message}" | Mode.Generator -> let maps = loadGameMaps datasetDescription generateDataForPretraining outputDirectory datasetBasePath maps stepsToSerialize | x -> failwithf $"Unexpected mode {x}." - - 0 \ No newline at end of file + + 0