initial commit
						commit
						ad8f97e674
					
				| 
						 | 
					@ -0,0 +1,222 @@
 | 
				
			||||||
 | 
					# The following command works for downloading when using Git for Windows:
 | 
				
			||||||
 | 
					# curl -LOf http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Download this file using PowerShell v3 under Windows with the following comand:
 | 
				
			||||||
 | 
					# Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# or wget:
 | 
				
			||||||
 | 
					# wget --no-check-certificate http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# User-specific files
 | 
				
			||||||
 | 
					*.suo
 | 
				
			||||||
 | 
					*.user
 | 
				
			||||||
 | 
					*.sln.docstates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build results
 | 
				
			||||||
 | 
					[Dd]ebug/
 | 
				
			||||||
 | 
					[Rr]elease/
 | 
				
			||||||
 | 
					x64/
 | 
				
			||||||
 | 
					[Bb]in/
 | 
				
			||||||
 | 
					[Oo]bj/
 | 
				
			||||||
 | 
					# build folder is nowadays used for build scripts and should not be ignored
 | 
				
			||||||
 | 
					#build/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NuGet Packages
 | 
				
			||||||
 | 
					*.nupkg
 | 
				
			||||||
 | 
					# The packages folder can be ignored because of Package Restore
 | 
				
			||||||
 | 
					**/packages/*
 | 
				
			||||||
 | 
					# except build/, which is used as an MSBuild target.
 | 
				
			||||||
 | 
					!**/packages/build/
 | 
				
			||||||
 | 
					# Uncomment if necessary however generally it will be regenerated when needed
 | 
				
			||||||
 | 
					#!**/packages/repositories.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# MSTest test Results
 | 
				
			||||||
 | 
					[Tt]est[Rr]esult*/
 | 
				
			||||||
 | 
					[Bb]uild[Ll]og.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*_i.c
 | 
				
			||||||
 | 
					*_p.c
 | 
				
			||||||
 | 
					*.ilk
 | 
				
			||||||
 | 
					*.meta
 | 
				
			||||||
 | 
					*.obj
 | 
				
			||||||
 | 
					*.pch
 | 
				
			||||||
 | 
					*.pdb
 | 
				
			||||||
 | 
					*.pgc
 | 
				
			||||||
 | 
					*.pgd
 | 
				
			||||||
 | 
					*.rsp
 | 
				
			||||||
 | 
					*.sbr
 | 
				
			||||||
 | 
					*.tlb
 | 
				
			||||||
 | 
					*.tli
 | 
				
			||||||
 | 
					*.tlh
 | 
				
			||||||
 | 
					*.tmp
 | 
				
			||||||
 | 
					*.tmp_proj
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					*.vspscc
 | 
				
			||||||
 | 
					*.vssscc
 | 
				
			||||||
 | 
					.builds
 | 
				
			||||||
 | 
					*.pidb
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					*.scc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# OS generated files #
 | 
				
			||||||
 | 
					.DS_Store*
 | 
				
			||||||
 | 
					Icon?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual C++ cache files
 | 
				
			||||||
 | 
					ipch/
 | 
				
			||||||
 | 
					*.aps
 | 
				
			||||||
 | 
					*.ncb
 | 
				
			||||||
 | 
					*.opensdf
 | 
				
			||||||
 | 
					*.sdf
 | 
				
			||||||
 | 
					*.cachefile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio profiler
 | 
				
			||||||
 | 
					*.psess
 | 
				
			||||||
 | 
					*.vsp
 | 
				
			||||||
 | 
					*.vspx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Guidance Automation Toolkit
 | 
				
			||||||
 | 
					*.gpState
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ReSharper is a .NET coding add-in
 | 
				
			||||||
 | 
					_ReSharper*/
 | 
				
			||||||
 | 
					*.[Rr]e[Ss]harper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TeamCity is a build add-in
 | 
				
			||||||
 | 
					_TeamCity*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# DotCover is a Code Coverage Tool
 | 
				
			||||||
 | 
					*.dotCover
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NCrunch
 | 
				
			||||||
 | 
					*.ncrunch*
 | 
				
			||||||
 | 
					.*crunch*.local.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Installshield output folder
 | 
				
			||||||
 | 
					[Ee]xpress/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# DocProject is a documentation generator add-in
 | 
				
			||||||
 | 
					DocProject/buildhelp/
 | 
				
			||||||
 | 
					DocProject/Help/*.HxT
 | 
				
			||||||
 | 
					DocProject/Help/*.HxC
 | 
				
			||||||
 | 
					DocProject/Help/*.hhc
 | 
				
			||||||
 | 
					DocProject/Help/*.hhk
 | 
				
			||||||
 | 
					DocProject/Help/*.hhp
 | 
				
			||||||
 | 
					DocProject/Help/Html2
 | 
				
			||||||
 | 
					DocProject/Help/html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Click-Once directory
 | 
				
			||||||
 | 
					publish/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Publish Web Output
 | 
				
			||||||
 | 
					*.Publish.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows Azure Build Output
 | 
				
			||||||
 | 
					csx
 | 
				
			||||||
 | 
					*.build.csdef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows Store app package directory
 | 
				
			||||||
 | 
					AppPackages/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Others
 | 
				
			||||||
 | 
					*.Cache
 | 
				
			||||||
 | 
					ClientBin/
 | 
				
			||||||
 | 
					[Ss]tyle[Cc]op.*
 | 
				
			||||||
 | 
					~$*
 | 
				
			||||||
 | 
					*~
 | 
				
			||||||
 | 
					*.dbmdl
 | 
				
			||||||
 | 
					*.[Pp]ublish.xml
 | 
				
			||||||
 | 
					*.pfx
 | 
				
			||||||
 | 
					*.publishsettings
 | 
				
			||||||
 | 
					modulesbin/
 | 
				
			||||||
 | 
					tempbin/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# EPiServer Site file (VPP)
 | 
				
			||||||
 | 
					AppData/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# RIA/Silverlight projects
 | 
				
			||||||
 | 
					Generated_Code/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Backup & report files from converting an old project file to a newer
 | 
				
			||||||
 | 
					# Visual Studio version. Backup files are not needed, because we have git ;-)
 | 
				
			||||||
 | 
					_UpgradeReport_Files/
 | 
				
			||||||
 | 
					Backup*/
 | 
				
			||||||
 | 
					UpgradeLog*.XML
 | 
				
			||||||
 | 
					UpgradeLog*.htm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# vim
 | 
				
			||||||
 | 
					*.txt~
 | 
				
			||||||
 | 
					*.swp
 | 
				
			||||||
 | 
					*.swo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Temp files when opening LibreOffice on ubuntu
 | 
				
			||||||
 | 
					.~lock.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# svn
 | 
				
			||||||
 | 
					.svn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CVS - Source Control
 | 
				
			||||||
 | 
					**/CVS/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Remainings from resolving conflicts in Source Control
 | 
				
			||||||
 | 
					*.orig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SQL Server files
 | 
				
			||||||
 | 
					**/App_Data/*.mdf
 | 
				
			||||||
 | 
					**/App_Data/*.ldf
 | 
				
			||||||
 | 
					**/App_Data/*.sdf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#LightSwitch generated files
 | 
				
			||||||
 | 
					GeneratedArtifacts/
 | 
				
			||||||
 | 
					_Pvt_Extensions/
 | 
				
			||||||
 | 
					ModelManifest.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# =========================
 | 
				
			||||||
 | 
					# Windows detritus
 | 
				
			||||||
 | 
					# =========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows image file caches
 | 
				
			||||||
 | 
					Thumbs.db
 | 
				
			||||||
 | 
					ehthumbs.db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Folder config file
 | 
				
			||||||
 | 
					Desktop.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Recycle Bin used on file shares
 | 
				
			||||||
 | 
					$RECYCLE.BIN/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Mac desktop service store files
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SASS Compiler cache
 | 
				
			||||||
 | 
					.sass-cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio 2014 CTP
 | 
				
			||||||
 | 
					**/*.sln.ide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio temp something
 | 
				
			||||||
 | 
					.vs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# dotnet stuff
 | 
				
			||||||
 | 
					project.lock.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# VS 2015+
 | 
				
			||||||
 | 
					*.vc.vc.opendb
 | 
				
			||||||
 | 
					*.vc.db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Rider
 | 
				
			||||||
 | 
					.idea/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Output folder used by Webpack or other FE stuff
 | 
				
			||||||
 | 
					**/node_modules/*
 | 
				
			||||||
 | 
					**/wwwroot/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SpecFlow specific
 | 
				
			||||||
 | 
					*.feature.cs
 | 
				
			||||||
 | 
					*.feature.xlsx.*
 | 
				
			||||||
 | 
					*.Specs_*.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#####
 | 
				
			||||||
 | 
					# End of core ignore list, below put you custom 'per project' settings (patterns or path)
 | 
				
			||||||
 | 
					#####
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					   // Use IntelliSense to find out which attributes exist for C# debugging
 | 
				
			||||||
 | 
					   // Use hover for the description of the existing attributes
 | 
				
			||||||
 | 
					   // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
 | 
				
			||||||
 | 
					   "version": "0.2.0",
 | 
				
			||||||
 | 
					   "configurations": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": ".NET Core Launch (console)",
 | 
				
			||||||
 | 
					            "type": "coreclr",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "preLaunchTask": "build",
 | 
				
			||||||
 | 
					            // If you have changed target frameworks, make sure to update the program path.
 | 
				
			||||||
 | 
					            "program": "${workspaceFolder}/test/bin/Debug/netcoreapp3.0/test.dll",
 | 
				
			||||||
 | 
					            "args": [],
 | 
				
			||||||
 | 
					            "cwd": "${workspaceFolder}/test",
 | 
				
			||||||
 | 
					            // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
 | 
				
			||||||
 | 
					            "console": "internalConsole",
 | 
				
			||||||
 | 
					            "stopAtEntry": false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "name": ".NET Core Attach",
 | 
				
			||||||
 | 
					            "type": "coreclr",
 | 
				
			||||||
 | 
					            "request": "attach",
 | 
				
			||||||
 | 
					            "processId": "${command:pickProcess}"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "version": "2.0.0",
 | 
				
			||||||
 | 
					    "tasks": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "label": "build",
 | 
				
			||||||
 | 
					            "command": "dotnet",
 | 
				
			||||||
 | 
					            "type": "process",
 | 
				
			||||||
 | 
					            "args": [
 | 
				
			||||||
 | 
					                "build",
 | 
				
			||||||
 | 
					                "${workspaceFolder}/test/test.csproj",
 | 
				
			||||||
 | 
					                "/property:GenerateFullPaths=true",
 | 
				
			||||||
 | 
					                "/consoleloggerparameters:NoSummary"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "problemMatcher": "$msCompile"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "label": "publish",
 | 
				
			||||||
 | 
					            "command": "dotnet",
 | 
				
			||||||
 | 
					            "type": "process",
 | 
				
			||||||
 | 
					            "args": [
 | 
				
			||||||
 | 
					                "publish",
 | 
				
			||||||
 | 
					                "${workspaceFolder}/test/test.csproj",
 | 
				
			||||||
 | 
					                "/property:GenerateFullPaths=true",
 | 
				
			||||||
 | 
					                "/consoleloggerparameters:NoSummary"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "problemMatcher": "$msCompile"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "label": "watch",
 | 
				
			||||||
 | 
					            "command": "dotnet",
 | 
				
			||||||
 | 
					            "type": "process",
 | 
				
			||||||
 | 
					            "args": [
 | 
				
			||||||
 | 
					                "watch",
 | 
				
			||||||
 | 
					                "run",
 | 
				
			||||||
 | 
					                "${workspaceFolder}/test/test.csproj",
 | 
				
			||||||
 | 
					                "/property:GenerateFullPaths=true",
 | 
				
			||||||
 | 
					                "/consoleloggerparameters:NoSummary"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "problemMatcher": "$msCompile"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,419 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public enum SearchSymbol
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        start,
 | 
				
			||||||
 | 
					        finish
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public class DirectedGraph<T>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private class SimpleCycleComparer : IEqualityComparer<IEnumerable<T>>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return x.SequenceEqual(y);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            public int GetHashCode(IEnumerable<T> obj)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return obj.Aggregate(0, (current, next) => current.GetHashCode() ^ next.GetHashCode());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected List<T> _vertices = new List<T>();
 | 
				
			||||||
 | 
					        protected Dictionary<T, HashSet<T>> _neighbors = new Dictionary<T, HashSet<T>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<T> Vertices { get { return _vertices; } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * GRAPH STRUCTURE METHODS
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddVertex(T vertex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (!VertexExists(vertex))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _vertices.Add(vertex);
 | 
				
			||||||
 | 
					                _neighbors.Add(vertex, new HashSet<T>());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddVertices(params T[] vertices)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var vertex in vertices)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                AddVertex(vertex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool VertexExists(T vertex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return Vertices.Contains(vertex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void RemoveVertex(T vertex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var edgesToRemove = new List<Tuple<T, T>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (VertexExists(vertex))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                foreach (var entry in _neighbors)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (entry.Value.Contains(vertex))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        edgesToRemove.Add(Tuple.Create(entry.Key, vertex));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (var edge in edgesToRemove)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    RemoveEdge(edge.Item1, edge.Item2);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _vertices.Remove(vertex);
 | 
				
			||||||
 | 
					                _neighbors.Remove(vertex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddEdge(T v, T u)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (VertexExists(v) && VertexExists(u))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _neighbors[v].Add(u);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void AddEdges(params Tuple<T, T>[] edges)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (var edge in edges)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                AddEdge(edge.Item1, edge.Item2);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void RemoveEdge(T v, T u)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _neighbors[v].Remove(u);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<T> Neighbors(T vertex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (VertexExists(vertex))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return _neighbors[vertex];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return Enumerable.Empty<T>();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * GRAPH ANALYSIS METHODS
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Dictionary<T, Dictionary<SearchSymbol, uint>> NodeDFS()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var discovered = new HashSet<T>();
 | 
				
			||||||
 | 
					            uint time = 0;
 | 
				
			||||||
 | 
					            var output = new Dictionary<T, Dictionary<SearchSymbol, uint>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var vertex in Vertices)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                output.Add(vertex, new Dictionary<SearchSymbol, uint>());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            void dfsHelper(T v)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                discovered.Add(v);
 | 
				
			||||||
 | 
					                time++;
 | 
				
			||||||
 | 
					                output[v].Add(SearchSymbol.start, time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach (var neighbor in Neighbors(v))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    if (!discovered.Contains(neighbor))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        dfsHelper(neighbor);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                time++;
 | 
				
			||||||
 | 
					                output[v].Add(SearchSymbol.finish, time);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var vertex in Vertices)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (!discovered.Contains(vertex))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    dfsHelper(vertex);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return output;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public bool Cyclic()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return StronglyConnectedComponents().Any((scc) => scc.Count() > 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<T> TopologicalSort()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var dfs = NodeDFS();
 | 
				
			||||||
 | 
					            var priority = new SortedList<uint, T>();
 | 
				
			||||||
 | 
					            foreach (var entry in dfs)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                priority.Add(entry.Value[SearchSymbol.finish], entry.Key);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return priority.Values.Reverse();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<IEnumerable<T>> StronglyConnectedComponents()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var preorder = new Dictionary<T, uint>();
 | 
				
			||||||
 | 
					            var lowlink = new Dictionary<T, uint>();
 | 
				
			||||||
 | 
					            var sccFound = new Dictionary<T, bool>();
 | 
				
			||||||
 | 
					            var sccQueue = new Stack<T>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = new List<List<T>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint preorderCounter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var source in Vertices)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (!sccFound.ContainsKey(source))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var queue = new Stack<T>();
 | 
				
			||||||
 | 
					                    queue.Push(source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    while (queue.Count > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var v = queue.Peek();
 | 
				
			||||||
 | 
					                        if (!preorder.ContainsKey(v))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            preorderCounter++;
 | 
				
			||||||
 | 
					                            preorder[v] = preorderCounter;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var done = true;
 | 
				
			||||||
 | 
					                        var vNeighbors = Neighbors(v);
 | 
				
			||||||
 | 
					                        foreach (var w in vNeighbors)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if (!preorder.ContainsKey(w))
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                queue.Push(w);
 | 
				
			||||||
 | 
					                                done = false;
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (done)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            lowlink[v] = preorder[v];
 | 
				
			||||||
 | 
					                            foreach (var w in vNeighbors)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                if (!sccFound.ContainsKey(w))
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    if (preorder[w] > preorder[v])
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        lowlink[v] = Math.Min(lowlink[v], lowlink[w]);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    else
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        lowlink[v] = Math.Min(lowlink[v], preorder[w]);
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            queue.Pop();
 | 
				
			||||||
 | 
					                            if (lowlink[v] == preorder[v])
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                sccFound[v] = true;
 | 
				
			||||||
 | 
					                                var scc = new List<T>
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    v
 | 
				
			||||||
 | 
					                                };
 | 
				
			||||||
 | 
					                                while (sccQueue.Count > 0 && preorder[sccQueue.Peek()] > preorder[v])
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    var k = sccQueue.Pop();
 | 
				
			||||||
 | 
					                                    sccFound[k] = true;
 | 
				
			||||||
 | 
					                                    scc.Add(k);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                result.Add(scc);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            else
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                sccQueue.Push(v);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public IEnumerable<IEnumerable<T>> SimpleCycles()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            void unblock(T thisnode, HashSet<T> blocked, Dictionary<T, HashSet<T>> B)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var stack = new Stack<T>();
 | 
				
			||||||
 | 
					                stack.Push(thisnode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                while (stack.Count > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var node = stack.Pop();
 | 
				
			||||||
 | 
					                    if (blocked.Contains(thisnode))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        blocked.Remove(thisnode);
 | 
				
			||||||
 | 
					                        if (B.ContainsKey(node))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            foreach (var n in B[node])
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                if (!stack.Contains(n))
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    stack.Push(n);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            B[node].Clear();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            List<List<T>> result = new List<List<T>>();
 | 
				
			||||||
 | 
					            var subGraph = Clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var sccs = new Stack<IEnumerable<T>>();
 | 
				
			||||||
 | 
					            foreach (var scc in StronglyConnectedComponents())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                sccs.Push(scc);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (sccs.Count > 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                var scc = new Stack<T>(sccs.Pop());
 | 
				
			||||||
 | 
					                var startNode = scc.Pop();
 | 
				
			||||||
 | 
					                var path = new Stack<T>();
 | 
				
			||||||
 | 
					                path.Push(startNode);
 | 
				
			||||||
 | 
					                var blocked = new HashSet<T>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    startNode
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                var closed = new HashSet<T>();
 | 
				
			||||||
 | 
					                var B = new Dictionary<T, HashSet<T>>();
 | 
				
			||||||
 | 
					                var stack = new Stack<Tuple<T, Stack<T>>>();
 | 
				
			||||||
 | 
					                stack.Push(Tuple.Create(startNode, new Stack<T>(subGraph.Neighbors(startNode))));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                while (stack.Count > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var entry = stack.Peek();
 | 
				
			||||||
 | 
					                    var thisnode = entry.Item1;
 | 
				
			||||||
 | 
					                    var neighbors = entry.Item2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (neighbors.Count > 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        var nextNode = neighbors.Pop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (nextNode.Equals(startNode))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            var resultPath = new List<T>();
 | 
				
			||||||
 | 
					                            foreach (var v in path)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                resultPath.Add(v);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            result.Add(resultPath);
 | 
				
			||||||
 | 
					                            foreach (var v in path)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                closed.Add(v);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else if (!blocked.Contains(nextNode))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            path.Push(nextNode);
 | 
				
			||||||
 | 
					                            stack.Push(Tuple.Create(nextNode, new Stack<T>(subGraph.Neighbors(nextNode))));
 | 
				
			||||||
 | 
					                            closed.Remove(nextNode);
 | 
				
			||||||
 | 
					                            blocked.Add(nextNode);
 | 
				
			||||||
 | 
					                            continue;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (neighbors.Count == 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (closed.Contains(thisnode))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            unblock(thisnode, blocked, B);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            foreach (var neighbor in subGraph.Neighbors(thisnode))
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                if (!B.ContainsKey(neighbor))
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    B[neighbor] = new HashSet<T>();
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                                B[neighbor].Add(thisnode);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        stack.Pop();
 | 
				
			||||||
 | 
					                        path.Pop();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                subGraph.RemoveVertex(startNode);
 | 
				
			||||||
 | 
					                var H = subGraph.SubGraph(scc.ToArray());
 | 
				
			||||||
 | 
					                var HSccs = H.StronglyConnectedComponents();
 | 
				
			||||||
 | 
					                foreach (var HScc in HSccs)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    sccs.Push(HScc);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return result.Distinct(new SimpleCycleComparer());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DirectedGraph<T> Clone()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var clone = new DirectedGraph<T>();
 | 
				
			||||||
 | 
					            clone.AddVertices(Vertices.ToArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var v in Vertices)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                foreach (var n in Neighbors(v))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    clone.AddEdge(v, n);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return clone;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DirectedGraph<T> SubGraph(params T[] subVertices)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var subGraph = new DirectedGraph<T>();
 | 
				
			||||||
 | 
					            subGraph.AddVertices(subVertices.ToArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var v in Vertices)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (Vertices.Contains(v))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    var neighbors = Neighbors(v);
 | 
				
			||||||
 | 
					                    foreach (var u in neighbors)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (subVertices.Contains(u))
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            subGraph.AddEdge(v, u);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return subGraph;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <TargetFramework>netstandard2.0</TargetFramework>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					namespace MoonTools.Core.Graph
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class UndirectedGraph<T>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Microsoft Visual Studio Solution File, Format Version 12.00
 | 
				
			||||||
 | 
					# Visual Studio 15
 | 
				
			||||||
 | 
					VisualStudioVersion = 15.0.26124.0
 | 
				
			||||||
 | 
					MinimumVisualStudioVersion = 15.0.26124.0
 | 
				
			||||||
 | 
					Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoonTools.Core.Graph", "Graph\MoonTools.Core.Graph.csproj", "{424ACD00-5613-4DBF-8D79-6509D7841D8A}"
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
 | 
					Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\test.csproj", "{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}"
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
 | 
					Global
 | 
				
			||||||
 | 
						GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
				
			||||||
 | 
							Debug|Any CPU = Debug|Any CPU
 | 
				
			||||||
 | 
							Debug|x64 = Debug|x64
 | 
				
			||||||
 | 
							Debug|x86 = Debug|x86
 | 
				
			||||||
 | 
							Release|Any CPU = Release|Any CPU
 | 
				
			||||||
 | 
							Release|x64 = Release|x64
 | 
				
			||||||
 | 
							Release|x86 = Release|x86
 | 
				
			||||||
 | 
						EndGlobalSection
 | 
				
			||||||
 | 
						GlobalSection(SolutionProperties) = preSolution
 | 
				
			||||||
 | 
							HideSolutionNode = FALSE
 | 
				
			||||||
 | 
						EndGlobalSection
 | 
				
			||||||
 | 
						GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Debug|x64.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Debug|x86.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Release|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Release|x64.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Release|x86.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{424ACD00-5613-4DBF-8D79-6509D7841D8A}.Release|x86.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Debug|x64.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Debug|x64.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Debug|x86.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Debug|x86.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Release|x64.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Release|x64.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Release|x86.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{423B5FFF-5B19-4D1C-ACF7-B5908E3E50EA}.Release|x86.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
						EndGlobalSection
 | 
				
			||||||
 | 
					EndGlobal
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,373 @@
 | 
				
			||||||
 | 
					using NUnit.Framework;
 | 
				
			||||||
 | 
					using FluentAssertions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using MoonTools.Core.Graph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Tests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class DirectedGraphTest
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddVertex()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertex(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Vertices, Does.Contain(4));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddVertices()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(4, 20, 69);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.IsTrue(myGraph.VertexExists(4));
 | 
				
			||||||
 | 
					            Assert.IsTrue(myGraph.VertexExists(20));
 | 
				
			||||||
 | 
					            Assert.IsTrue(myGraph.VertexExists(69));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddEdge()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(5, 6);
 | 
				
			||||||
 | 
					            myGraph.AddEdge(5, 6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(5), Does.Contain(6));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void AddEdges()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(1), Does.Contain(2));
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(2), Does.Contain(3));
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(2), Does.Contain(4));
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(3), Does.Contain(4));
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(1), Does.Not.Contain(4));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void RemoveEdge()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.RemoveEdge(2, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(2), Does.Not.Contain(3));
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Neighbors(2), Does.Contain(4));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void RemoveVertex()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.RemoveVertex(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            myGraph.Vertices.Should().NotContain(2);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(1).Should().NotContain(2);
 | 
				
			||||||
 | 
					            myGraph.Neighbors(3).Should().Contain(4);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void NodeDFS()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<char>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices('a', 'b', 'c', 'd');
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create('a', 'b'),
 | 
				
			||||||
 | 
					                Tuple.Create('a', 'c'),
 | 
				
			||||||
 | 
					                Tuple.Create('b', 'd')
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = myGraph.NodeDFS();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(result['a'][SearchSymbol.start], Is.EqualTo(1));
 | 
				
			||||||
 | 
					            Assert.That(result['a'][SearchSymbol.finish], Is.EqualTo(8));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(result['b'][SearchSymbol.start], Is.EqualTo(2));
 | 
				
			||||||
 | 
					            Assert.That(result['b'][SearchSymbol.finish], Is.EqualTo(5));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(result['c'][SearchSymbol.start], Is.EqualTo(6));
 | 
				
			||||||
 | 
					            Assert.That(result['c'][SearchSymbol.finish], Is.EqualTo(7));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(result['d'][SearchSymbol.start], Is.EqualTo(3));
 | 
				
			||||||
 | 
					            Assert.That(result['d'][SearchSymbol.finish], Is.EqualTo(4));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void TopologicalSortSimple()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var simpleGraph = new DirectedGraph<char>();
 | 
				
			||||||
 | 
					            simpleGraph.AddVertices('a', 'b', 'c', 'd');
 | 
				
			||||||
 | 
					            simpleGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create('a', 'b'),
 | 
				
			||||||
 | 
					                Tuple.Create('a', 'c'),
 | 
				
			||||||
 | 
					                Tuple.Create('b', 'a'),
 | 
				
			||||||
 | 
					                Tuple.Create('b', 'd')
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(simpleGraph.TopologicalSort(), Is.EqualTo(new char[] { 'a', 'c', 'b', 'd' }));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void TopologicalSortComplex()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var complexGraph = new DirectedGraph<char>();
 | 
				
			||||||
 | 
					            complexGraph.AddVertices('a', 'b', 'c', 'd', 'e', 'f', 'g', 't', 'm');
 | 
				
			||||||
 | 
					            complexGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create('a', 'b'),
 | 
				
			||||||
 | 
					                Tuple.Create('a', 'c'),
 | 
				
			||||||
 | 
					                Tuple.Create('a', 'd'),
 | 
				
			||||||
 | 
					                Tuple.Create('b', 'f'),
 | 
				
			||||||
 | 
					                Tuple.Create('b', 'g'),
 | 
				
			||||||
 | 
					                Tuple.Create('c', 'g'),
 | 
				
			||||||
 | 
					                Tuple.Create('e', 't'),
 | 
				
			||||||
 | 
					                Tuple.Create('t', 'm')
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(
 | 
				
			||||||
 | 
					                complexGraph.TopologicalSort(),
 | 
				
			||||||
 | 
					                Is.EqualTo(new char[] { 'e', 't', 'm', 'a', 'd', 'c', 'b', 'g', 'f' })
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void StronglyConnectedComponentsSimple()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var simpleGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            simpleGraph.AddVertices(1, 2, 3);
 | 
				
			||||||
 | 
					            simpleGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 1)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = simpleGraph.StronglyConnectedComponents();
 | 
				
			||||||
 | 
					            var scc = new int[] { 1, 2, 3 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(scc);
 | 
				
			||||||
 | 
					            Assert.That(result.Count, Is.EqualTo(1));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void StronglyConnectedComponentsMedium()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var mediumGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            mediumGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            mediumGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(1, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(1, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(4, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = mediumGraph.StronglyConnectedComponents();
 | 
				
			||||||
 | 
					            var sccA = new int[] { 2, 3, 4 };
 | 
				
			||||||
 | 
					            var sccB = new int[] { 1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(sccA);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(sccB);
 | 
				
			||||||
 | 
					            Assert.That(result.Count, Is.EqualTo(2));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void StronglyConnectedComponentsComplex()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var complexGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            complexGraph.AddVertices(1, 2, 3, 4, 5, 6, 7, 8);
 | 
				
			||||||
 | 
					            complexGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 8),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 7),
 | 
				
			||||||
 | 
					                Tuple.Create(4, 5),
 | 
				
			||||||
 | 
					                Tuple.Create(5, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(5, 6),
 | 
				
			||||||
 | 
					                Tuple.Create(7, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(7, 6),
 | 
				
			||||||
 | 
					                Tuple.Create(8, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(8, 7)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = complexGraph.StronglyConnectedComponents();
 | 
				
			||||||
 | 
					            var sccA = new int[] { 3, 4, 5, 7 };
 | 
				
			||||||
 | 
					            var sccB = new int[] { 1, 2, 8 };
 | 
				
			||||||
 | 
					            var sccC = new int[] { 6 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(sccA);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(sccB);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(sccC);
 | 
				
			||||||
 | 
					            Assert.That(result.Count, Is.EqualTo(3));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void Clone()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var clone = myGraph.Clone();
 | 
				
			||||||
 | 
					            Assert.That(clone, Is.Not.EqualTo(myGraph));
 | 
				
			||||||
 | 
					            clone.Vertices.Should().BeEquivalentTo(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            clone.Neighbors(1).Should().BeEquivalentTo(1, 2);
 | 
				
			||||||
 | 
					            clone.Neighbors(2).Should().BeEquivalentTo(3, 1);
 | 
				
			||||||
 | 
					            clone.Neighbors(3).Should().BeEquivalentTo(4);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void SubGraph()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var subGraph = myGraph.SubGraph(1, 2, 3);
 | 
				
			||||||
 | 
					            subGraph.Vertices.Should().BeEquivalentTo(1, 2, 3);
 | 
				
			||||||
 | 
					            subGraph.Neighbors(1).Should().BeEquivalentTo(1, 2);
 | 
				
			||||||
 | 
					            subGraph.Neighbors(2).Should().BeEquivalentTo(1, 3);
 | 
				
			||||||
 | 
					            subGraph.Neighbors(3).Should().NotContain(4);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void SimpleCyclesSimple()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(0, 1, 2);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(0, 0),
 | 
				
			||||||
 | 
					                Tuple.Create(0, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(0, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 0),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 2)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = myGraph.SimpleCycles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cycleA = new int[] { 0 };
 | 
				
			||||||
 | 
					            var cycleB = new int[] { 0, 1, 2 };
 | 
				
			||||||
 | 
					            var cycleC = new int[] { 0, 2 };
 | 
				
			||||||
 | 
					            var cycleD = new int[] { 1, 2 };
 | 
				
			||||||
 | 
					            var cycleE = new int[] { 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleA);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleB);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleC);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleD);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleE);
 | 
				
			||||||
 | 
					            result.Should().HaveCount(5);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void SimpleCyclesComplex()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(0, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 0),
 | 
				
			||||||
 | 
					                Tuple.Create(0, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4),
 | 
				
			||||||
 | 
					                Tuple.Create(4, 5),
 | 
				
			||||||
 | 
					                Tuple.Create(5, 0),
 | 
				
			||||||
 | 
					                Tuple.Create(0, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(1, 6),
 | 
				
			||||||
 | 
					                Tuple.Create(6, 7),
 | 
				
			||||||
 | 
					                Tuple.Create(7, 8),
 | 
				
			||||||
 | 
					                Tuple.Create(8, 0),
 | 
				
			||||||
 | 
					                Tuple.Create(8, 9)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var result = myGraph.SimpleCycles();
 | 
				
			||||||
 | 
					            var cycleA = new int[] { 0, 3 };
 | 
				
			||||||
 | 
					            var cycleB = new int[] { 0, 1, 2, 3, 4, 5 };
 | 
				
			||||||
 | 
					            var cycleC = new int[] { 0, 1, 2, 3 };
 | 
				
			||||||
 | 
					            var cycleD = new int[] { 0, 3, 4, 5 };
 | 
				
			||||||
 | 
					            var cycleE = new int[] { 0, 1, 6, 7, 8 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleA);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleB);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleC);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleD);
 | 
				
			||||||
 | 
					            result.Should().ContainEquivalentOf(cycleE);
 | 
				
			||||||
 | 
					            result.Should().HaveCount(5);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void Cyclic()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 1),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Cyclic(), Is.True);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Test]
 | 
				
			||||||
 | 
					        public void Acyclic()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var myGraph = new DirectedGraph<int>();
 | 
				
			||||||
 | 
					            myGraph.AddVertices(1, 2, 3, 4);
 | 
				
			||||||
 | 
					            myGraph.AddEdges(
 | 
				
			||||||
 | 
					                Tuple.Create(1, 2),
 | 
				
			||||||
 | 
					                Tuple.Create(2, 3),
 | 
				
			||||||
 | 
					                Tuple.Create(3, 4)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Assert.That(myGraph.Cyclic(), Is.False);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					<Project Sdk="Microsoft.NET.Sdk">
 | 
				
			||||||
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <TargetFramework>netcoreapp3.0</TargetFramework>
 | 
				
			||||||
 | 
					    <IsPackable>false</IsPackable>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <PackageReference Include="nunit" Version="3.12.0"/>
 | 
				
			||||||
 | 
					    <PackageReference Include="NUnit3TestAdapter" Version="3.13.0"/>
 | 
				
			||||||
 | 
					    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0"/>
 | 
				
			||||||
 | 
					    <PackageReference Include="FluentAssertions" Version="5.9.0"/>
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <ProjectReference Include="..\Graph\MoonTools.Core.Graph.csproj" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
		Loading…
	
		Reference in New Issue