diff --git a/hw5/LocalNetworkGraph/LocalNetworkGraph.sln b/hw5/LocalNetworkGraph/LocalNetworkGraph.sln new file mode 100644 index 0000000..7f7828b --- /dev/null +++ b/hw5/LocalNetworkGraph/LocalNetworkGraph.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "LocalNetworkGraph", "LocalNetworkGraph\LocalNetworkGraph.fsproj", "{3DD18E22-393F-4B15-ACD5-AF3DA21A5CC2}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LocalNetworkGraphTests", "LocalNetworkGraphTests\LocalNetworkGraphTests.fsproj", "{61D8FBF7-9B8A-461B-A27F-0416A7085DB3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3DD18E22-393F-4B15-ACD5-AF3DA21A5CC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3DD18E22-393F-4B15-ACD5-AF3DA21A5CC2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3DD18E22-393F-4B15-ACD5-AF3DA21A5CC2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3DD18E22-393F-4B15-ACD5-AF3DA21A5CC2}.Release|Any CPU.Build.0 = Release|Any CPU + {61D8FBF7-9B8A-461B-A27F-0416A7085DB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61D8FBF7-9B8A-461B-A27F-0416A7085DB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61D8FBF7-9B8A-461B-A27F-0416A7085DB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61D8FBF7-9B8A-461B-A27F-0416A7085DB3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {70F6F8E0-B63F-4D25-9686-6ACC16C8D9F5} + EndGlobalSection +EndGlobal diff --git a/hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetwork.fs b/hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetwork.fs new file mode 100644 index 0000000..d05e288 --- /dev/null +++ b/hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetwork.fs @@ -0,0 +1,82 @@ +module LocalNetwork + +open System + + +/// Local network working process model. +type LocalNetwork(computersCommunication: int list list, OSOfComputers: string list, probabilityInfectionForOS: float list) = + + /// Number of computers in local network. + let numberOfComputers () = List.length computersCommunication + + /// Random number sensor for computers. On every step check if the computer is infected. + let rndSensorValue = new Random() + + /// Returns the probability to be infected for computer with specific OS. + let probabylityOfInfectionForOS operSys = probabilityInfectionForOS.[List.findIndex (fun x -> x = operSys) OSOfComputers] * 100.0 + + /// Finds probabylity of infection for computer. + let probabilityOfInfection vertex = probabylityOfInfectionForOS <| OSOfComputers.[vertex] + + /// Checks if the current step infects computer. + let isInfectedThisStep vertex = + probabilityOfInfection vertex >= double(rndSensorValue.Next(0, 100)) + + /// Checks if the network can be infected. + let networkCanBeInfected = List.exists (fun x -> abs(x) > 0.001) probabilityInfectionForOS + + /// Checks if the neighbours of the computer can be infected. + let neighboursCanBeInfected vertex infected = + List.exists (fun x -> not (List.contains x infected) && abs(probabilityOfInfection x) > 0.001) computersCommunication.[vertex] + + /// Tries to infect neighbours. + let tryInfectNeighbours infected vertex = + let rec tryInfectNeighboursRec infected vertex currVrtx = + if currVrtx = numberOfComputers() then infected + elif isInfectedThisStep currVrtx && not (List.contains currVrtx infected) && List.contains currVrtx computersCommunication.[vertex] then + tryInfectNeighboursRec (currVrtx :: infected) vertex (currVrtx + 1) + else tryInfectNeighboursRec infected vertex (currVrtx + 1) + tryInfectNeighboursRec infected vertex 0 + + /// Tries to infect all the vertexes that are connected with infected. + let tryInfectNeighboursOfInfected infected = + let rec tryInfectNeighboursOfInfectedRec infected leftVrtxs = + match leftVrtxs with + | [] -> infected + | h :: t -> tryInfectNeighboursOfInfectedRec (tryInfectNeighbours infected h) t + tryInfectNeighboursOfInfectedRec infected infected + + + /// Infects first computer. + let infectFirst () = + let rec infectFirstRec acc = + if isInfectedThisStep acc then acc + else infectFirstRec <| (acc + 1) % numberOfComputers() + infectFirstRec 0 + + /// Prints the information about the state of the network. + let printInf infected = + let rec printRec infected currVertex = + if currVertex < numberOfComputers() then + if List.contains currVertex infected then printfn "%s%d" "INFECTED: " currVertex + else printfn "%s%d" "Not infected: " currVertex + printRec infected (currVertex + 1) + printf "%s" "\n" + printRec infected 0 + + /// Infects all the vertexes that are possible to infect. + let rec infectAll = + if not networkCanBeInfected then [] + else + let rec infectAllRec infected = + if List.length infected = 0 then + printInf infected + infectAllRec (infectFirst () :: infected) + elif (List.length infected = numberOfComputers () || List.forall (fun x -> not (neighboursCanBeInfected x infected)) infected) then infected + else + printInf infected + infectAllRec (tryInfectNeighboursOfInfected infected) + infectAllRec [] + + /// Infects all the computers with virus. Returns infected computers. + member public this.Infected = infectAll diff --git a/hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetworkGraph.fsproj b/hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetworkGraph.fsproj new file mode 100644 index 0000000..cf05dbe --- /dev/null +++ b/hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetworkGraph.fsproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + diff --git a/hw5/LocalNetworkGraph/LocalNetworkGraph/Program.fs b/hw5/LocalNetworkGraph/LocalNetworkGraph/Program.fs new file mode 100644 index 0000000..23c15b9 --- /dev/null +++ b/hw5/LocalNetworkGraph/LocalNetworkGraph/Program.fs @@ -0,0 +1,11 @@ +// Learn more about F# at http://fsharp.org + +open System +open LocalNetwork + +[] +let main argv = + printfn "%A" <| LocalNetwork([[1; 3]; [0]; [3]; [2; 1]], ["Windows"; "Linux"; "Linux"; "Mac OS"], + [0.7; 0.1; 0.1; 0.9]).Infected + + 0 // return an integer exit code diff --git a/hw5/LocalNetworkGraph/LocalNetworkGraphTests/LocalNetworkGraphTests.fsproj b/hw5/LocalNetworkGraph/LocalNetworkGraphTests/LocalNetworkGraphTests.fsproj new file mode 100644 index 0000000..c8c48fb --- /dev/null +++ b/hw5/LocalNetworkGraph/LocalNetworkGraphTests/LocalNetworkGraphTests.fsproj @@ -0,0 +1,32 @@ + + + + netcoreapp3.1 + + false + true + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + diff --git a/hw5/LocalNetworkGraph/LocalNetworkGraphTests/LocalNetworkTests.fs b/hw5/LocalNetworkGraph/LocalNetworkGraphTests/LocalNetworkTests.fs new file mode 100644 index 0000000..3d58e6d --- /dev/null +++ b/hw5/LocalNetworkGraph/LocalNetworkGraphTests/LocalNetworkTests.fs @@ -0,0 +1,39 @@ +module LocalNetworkGraphTests + +open NUnit.Framework +open LocalNetwork +open FsUnit + +let testCases1 = + [ + [[1]; [0]], ["Linux"; "Windows"], [0.3; 0.7], [0; 1] + [[1]; [0]], ["Linux"; "Windows"], [1.0; 1.0], [0; 1] + [[1]; [0]], ["Mac OS"; "Linux"], [0.7; 0.0], [0] + [[1; 3]; [0]; [3]; [2; 1]], ["Windows"; "Linux"; "Linux"; "Mac OS"], [0.7; 0.1; 0.1; 0.9], [0; 1; 2; 3] + [[1; 2; 3; 4]; [0; 2; 3; 4]; [0; 1; 3; 4]; [0; 1; 2; 3]; [0; 1; 2; 3; 4]], + ["WIndows"; "Windows"; "Linux"; "Linux"; "Mac OS"], [0.5; 0.5; 0.2; 0.2; 1.0], [0; 1; 2; 3; 4] + ] |> List.map (fun (communicationComputers, operSys, probabOfInf, infected) -> + TestCaseData(communicationComputers, operSys, probabOfInf, infected)) + +let testCases2 = + [ + [[1]; [0]], ["Linux"; "Windows"], [0.0; 0.0] + [[1; 2; 3; 4]; [0; 2; 3; 4]; [0; 1; 3; 4]; [0; 1; 2; 3]; [0; 1; 2; 3; 4]], + ["WIndows"; "Windows"; "Linux"; "Linux"; "Mac OS"], [0.0; 0.0; 0.0; 0.0; 0.0] + ] |> List.map (fun (communicationComputers, operSys, probabOfInf) -> + TestCaseData(communicationComputers, operSys, probabOfInf)) + +[] +[] +let ``Checks if contains vertexes that should be infected`` communication operSys probabOfInf infected = + LocalNetwork(communication, operSys, probabOfInf).Infected |> List.forall (fun x -> List.contains x infected) |> should equal true + +[] +[] +let ``Checks if vertexes that should be infected are contained in result`` communication operSys probabOfInf infected = + List.forall (fun x -> LocalNetwork(communication, operSys, probabOfInf).Infected |> List.contains x) infected |> should equal true + +[] +[] +let ``Checks if the algorithm works correctly when probabylity of infection is 0 for all computers`` communication operSys probabOfInf = + LocalNetwork(communication, operSys, probabOfInf).Infected |> List.length = 0 |> should equal true \ No newline at end of file