Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local network graph is ready #8

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions hw5/LocalNetworkGraph/LocalNetworkGraph.sln
Original file line number Diff line number Diff line change
@@ -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
80 changes: 80 additions & 0 deletions hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetwork.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
module LocalNetwork

open System


/// Local network working process model.
type LocalNetwork(computersCommunication: int list list, OSOfComputers: string list, probabilityInfectionForOS: float list) =

/// Infected computers.
let mutable infected = []

/// Infected this step.
let mutable newInfected = []

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так нет, функциональный стиль --- это не когда у нас поле немутабельного типа, котрое по сути представляет собой глобальную переменную, его кто-то где-то внутри меняет, потом его надо не забыть сбросить в пустой список и т.д., функциональный стиль --- это когда у нас практически нет состояния и мы всё, что надо, просто возвращаем из функций или передаём как параметр, так что поток данных в программе в точности соответствует потоку исполнения. Тут можно было сделать так, чтобы tryInfectNeighbours выдавал список заражённых, а вместо List.iter(fun x -> tryInfectNeighbours x) infected (что само по себе не очень, правильно List.iter tryInfectNeighbours infected) сделать List.map и List.concat

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И мне кажется, как раз забыли сбросить newInfected :)


/// Number of computers in local network.
let numberOfComputers () = List.length computersCommunication

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это можно было сделать полем, ведь 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 =
List.exists (fun x -> not (List.contains x infected) && abs(probabilityOfInfection x) > 0.001) computersCommunication.[vertex]

/// Tries to infect neighbours.
let tryInfectNeighbours vertex =
let tryInfectNeighboursRec vertex =
computersCommunication.[vertex]
|> List.iter (fun x -> if not (List.contains x infected) && isInfectedThisStep x then newInfected <- newInfected @ [x])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newInfected @ [x] или x :: newInfected?

tryInfectNeighboursRec vertex

/// 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 () =
let rec printRec currVertex =
if currVertex < numberOfComputers() then
if List.contains currVertex infected then printfn "%s%d" "INFECTED: " currVertex
else printfn "%s%d" "Not infected: " currVertex
printRec (currVertex + 1)
printf "%s" "\n"
printRec 0

/// Infects all the vertexes that are possible to infect.
let rec infectAll =
if not networkCanBeInfected then infected
else
let rec infectAllRec acc =
if List.length infected = 0 then
infected <- infected @ [infectFirst ()]
printInf ()
infectAllRec 0
elif (List.length infected = numberOfComputers () || List.forall (fun x -> not (neighboursCanBeInfected x)) infected) then infected
else
List.iter(fun x -> tryInfectNeighbours x) infected
infected <- infected @ newInfected
printInf ()
infectAllRec 0
infectAllRec 0

/// Infects all the computers with virus. Returns infected computers.
member public this.Infected = infectAll

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тогда оно должно называться как что-то вроде "Infect"

13 changes: 13 additions & 0 deletions hw5/LocalNetworkGraph/LocalNetworkGraph/LocalNetworkGraph.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="LocalNetwork.fs" />
<Compile Include="Program.fs" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions hw5/LocalNetworkGraph/LocalNetworkGraph/Program.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Learn more about F# at http://fsharp.org

open System
open LocalNetwork

[<EntryPoint>]
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<IsPackable>false</IsPackable>
<GenerateProgramFile>true</GenerateProgramFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FsUnit" Version="3.8.1" />
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
</ItemGroup>

<ItemGroup>
<Compile Include="LocalNetworkTests.fs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\LocalNetworkGraph\LocalNetworkGraph.fsproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>

</Project>
39 changes: 39 additions & 0 deletions hw5/LocalNetworkGraph/LocalNetworkGraphTests/LocalNetworkTests.fs
Original file line number Diff line number Diff line change
@@ -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))

[<Test>]
[<TestCaseSource("testCases1")>]
let ``Checks if contains vertexes that should be infected`` communication operSys probabOfInf infected =
LocalNetwork(communication, operSys, probabOfInf).Infected.TrueForAll(fun x -> List.contains x infected) |> should equal true

[<Test>]
[<TestCaseSource("testCases1")>]
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.Contains(x)) infected |> should equal true

[<Test>]
[<TestCaseSource("testCases2")>]
let ``Checks if the algorithm works correctly when probabylity of infection is 0 for all computers`` communication operSys probabOfInf =
LocalNetwork(communication, operSys, probabOfInf).Infected.Count = 0 |> should equal true