diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 4094210..5d32dda 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -4,23 +4,38 @@
"tools": {
"dotnet-format": {
"version": "5.1.250801",
- "commands": ["dotnet-format"],
+ "commands": [
+ "dotnet-format"
+ ],
"rollForward": false
},
"dotnet-script": {
"version": "1.4.0",
- "commands": ["dotnet-script"],
+ "commands": [
+ "dotnet-script"
+ ],
"rollForward": false
},
"csharpier": {
"version": "0.29.2",
- "commands": ["dotnet-csharpier"],
+ "commands": [
+ "dotnet-csharpier"
+ ],
"rollForward": false
},
"husky": {
"version": "0.6.1",
- "commands": ["husky"],
+ "commands": [
+ "husky"
+ ],
+ "rollForward": false
+ },
+ "fantomas": {
+ "version": "6.3.16",
+ "commands": [
+ "fantomas"
+ ],
"rollForward": false
}
}
-}
+}
\ No newline at end of file
diff --git a/SharpGraph.Builder/Compiler.fs b/SharpGraph.Builder/Compiler.fs
index 81030ae..63bd2b5 100644
--- a/SharpGraph.Builder/Compiler.fs
+++ b/SharpGraph.Builder/Compiler.fs
@@ -1,8 +1,9 @@
namespace SharpGraph.Builder
-///
-///
-///
+///
+/// Compiler module to compiel expressions representing graphs into
+/// graph objects.
+///
module Compiler =
open SharpGraph
open Microsoft.FSharp.Collections
@@ -121,28 +122,19 @@ module Compiler =
| UnaryExp(e, op) -> HandleUnaryExp e op
| BinaryOperatorExp(op, e1, e2) -> BinaryOperatorExp op e1 e2
- ///
- ///
- ///
+
let Parse code =
- System.Diagnostics.Debug.WriteLine("BEGIN PARSING")
- match runParserOnString (pExpression .>> eof) () "Tokamak reaction stream" code with
+ match runParserOnString (pExpression .>> eof) () "Graph compile stream" code with
| Success(result, _, _) ->
- System.Diagnostics.Debug.WriteLine("FINISH PARSING")
result
| Failure(msg, _, _) ->
- System.Diagnostics.Debug.WriteLine("Error " + msg + "Reactor core containment failed!")
failwith msg
+ ///
+ /// Compiles the given string into a Graph object.
+ ///
+ ///The input string to build the graph
+ ///Graph object
let Compile (text: string) =
- let result = HandleExpression(Parse text)
-
- System.Console.WriteLine(
- "graph number of nodes "
- + string (result.GetNodes().Count)
- + " and edges: "
- + string (result.GetEdges().Count)
- )
-
- result
+ HandleExpression(Parse text)
diff --git a/SharpGraph.Builder/SharpGraph.Builder.fsproj b/SharpGraph.Builder/SharpGraph.Builder.fsproj
index 7865310..ce2985b 100644
--- a/SharpGraph.Builder/SharpGraph.Builder.fsproj
+++ b/SharpGraph.Builder/SharpGraph.Builder.fsproj
@@ -3,7 +3,7 @@
SharpGraphLib.Builder
net8.0
README.md
- 1.0.3
+ 1.0.4
Jonathan Hough
Jonathan Hough
true
diff --git a/SharpGraph.Tests/test/CycleTest.cs b/SharpGraph.Tests/test/CycleTest.cs
index d9d57fc..aed00a5 100644
--- a/SharpGraph.Tests/test/CycleTest.cs
+++ b/SharpGraph.Tests/test/CycleTest.cs
@@ -3,13 +3,6 @@
// Copyright Licensed under the MIT license.
// See LICENSE file in the samples root for full license information.
//
-
-using System;
-//
-// Copyright (C) 2023 Jonathan Hough.
-// Copyright Licensed under the MIT license.
-// See LICENSE file in the samples root for full license information.
-//
using Xunit;
namespace SharpGraph
diff --git a/SharpGraph.Tests/test/GraphContractionTest.cs b/SharpGraph.Tests/test/GraphContractionTest.cs
new file mode 100644
index 0000000..33e4630
--- /dev/null
+++ b/SharpGraph.Tests/test/GraphContractionTest.cs
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2023 Jonathan Hough.
+// Copyright Licensed under the MIT license.
+// See LICENSE file in the samples root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+namespace SharpGraph
+{
+ public class GraphContractionTest
+ {
+ [Theory]
+ [InlineData(6, "1", "2", 5, 10, 4)]
+ [InlineData(10, "2", "6", 9, 36, 8)]
+ public void TestContractEdgeFromComplete(
+ uint totalNodeCount,
+ string nodeToKeep,
+ string nodeToRemove,
+ int expectedNumberOfNodes,
+ int expectedNumberOfEdges,
+ int expectedAdjacentToKeptNode
+ )
+ {
+ var edgeToRemove = new Edge(nodeToKeep, nodeToRemove);
+ var g = GraphGenerator.CreateComplete(totalNodeCount);
+ var h = g.ContractEdge(edgeToRemove, new Node(nodeToKeep));
+
+ Assert.Equal(expectedNumberOfNodes, h.GetNodes().Count);
+ Assert.Equal(expectedNumberOfEdges, h.GetEdges().Count);
+ Assert.Equal(expectedAdjacentToKeptNode, h.GetAdjacent(new Node(nodeToKeep)).Count);
+ }
+
+ [Fact]
+ public void TestContractionKeepsComponents()
+ {
+ var e1 = new Edge("1", "2");
+ var e2 = new Edge("2", "3");
+ var e3 = new Edge("2", "4");
+ var e4 = new Edge("5", "8");
+ var edges = new List { e1, e2, e3, e4 };
+ var g = new Graph(edges);
+ foreach (var e in g.GetEdges())
+ {
+ g.AddComponent(e);
+ }
+
+ var h = g.ContractEdge(e1, new Node("1"));
+
+ Assert.Equal(5, h.GetNodes().Count);
+ Assert.Equal(3, h.GetEdges().Count);
+ Assert.Equal(2, h.GetAdjacent(new Node("1")).Count);
+
+ // edge that was not updated should have kept the component
+ Assert.True(h.HasComponent(e4));
+ }
+ }
+}
diff --git a/SharpGraph/SharpGraph.csproj b/SharpGraph/SharpGraph.csproj
index 101a937..9786562 100644
--- a/SharpGraph/SharpGraph.csproj
+++ b/SharpGraph/SharpGraph.csproj
@@ -4,7 +4,7 @@
net8.0
SharpGraphLib
README.md
- 1.0.3
+ 1.0.4
Jonathan Hough
Jonathan Hough
diff --git a/SharpGraph/src/core/Graph.Contraction.cs b/SharpGraph/src/core/Graph.Contraction.cs
new file mode 100644
index 0000000..feec98d
--- /dev/null
+++ b/SharpGraph/src/core/Graph.Contraction.cs
@@ -0,0 +1,84 @@
+//
+// Copyright (C) 2023 Jonathan Hough.
+// Copyright Licensed under the MIT license.
+// See LICENSE file in the samples root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace SharpGraph
+{
+ public partial class Graph
+ {
+ ///
+ /// Contracts the edge from the graph. This essentially removes the edge form the graph.
+ /// Incident edges will be reassigned to connect to the "keep" node, which is one of the
+ /// two nodes of the to-be-deleted edge.
+ /// Edges that previously connected to the to-be-deleted node, will be deleted, and new edges to
+ /// the to-be-kept node will be created.
+ /// For edges not incident with the edge that is to be deleted, the edges in the returned graph will
+ /// be copies, including any components.
+ ///
+ /// Edge to be deleted.
+ /// Node of deleted edge to keep in output graph.
+ /// Graph with edge removed.
+ public Graph ContractEdge(Edge edge, Node keep)
+ {
+ if (this.GetEdges().Contains(edge) == false)
+ {
+ throw new Exception("Edge does not exist on this graph.");
+ }
+
+ if (!edge.Nodes().Contains(keep))
+ {
+ throw new Exception(
+ "Node to keep does not exist in the edge ot remove. Cannot remove edge."
+ );
+ }
+
+ var removeNode = keep == edge.To() ? edge.From() : edge.To();
+ var incident = this.GetIncidentEdges(removeNode);
+ var toRemove = new HashSet();
+ var newEdges = new HashSet();
+ toRemove.Add(edge);
+ foreach (var e in incident)
+ {
+ if (toRemove.Contains(e))
+ {
+ continue;
+ }
+
+ if (!e.Nodes().Contains(keep))
+ {
+ if (removeNode == e.To())
+ {
+ toRemove.Add(e);
+ var rex = new Edge(keep, e.From());
+ newEdges.Add(rex);
+ }
+ else if (removeNode == e.From())
+ {
+ toRemove.Add(e);
+ var rex = new Edge(keep, e.To());
+ newEdges.Add(rex);
+ }
+ }
+ }
+
+ var g = this.Copy();
+ foreach (var deadEdge in toRemove)
+ {
+ g.RemoveEdge(deadEdge);
+ }
+
+ g.RemoveNode(removeNode);
+ foreach (var newEdge in newEdges)
+ {
+ g.AddEdge(newEdge);
+ }
+
+ return g;
+ }
+ }
+}
diff --git a/SharpGraph/src/core/Graph.cs b/SharpGraph/src/core/Graph.cs
index 1d1e996..8da3a8b 100644
--- a/SharpGraph/src/core/Graph.cs
+++ b/SharpGraph/src/core/Graph.cs
@@ -353,7 +353,7 @@ public bool RemoveNode(Node node)
if (incidentEdges != null)
{
this.edges.RemoveAll(e => incidentEdges.Contains(e));
- incidentEdges.RemoveWhere(e => incidentEdges.Contains(e));
+ incidentEdges.RemoveWhere(e => e.Equals(e));
}
this.nodes.Remove(node);
@@ -407,13 +407,13 @@ public bool RemoveEdge(Edge edge)
var fromIncidentEdges = this.incidenceMap[f];
if (fromIncidentEdges != null)
{
- fromIncidentEdges.RemoveWhere(e => e.Equals(edge));
+ int i = fromIncidentEdges.RemoveWhere(e => e.Equals(edge));
}
var toIncidentEdges = this.incidenceMap[t];
if (toIncidentEdges != null)
{
- toIncidentEdges.RemoveWhere(e => e.Equals(edge));
+ int i = toIncidentEdges.RemoveWhere(e => e.Equals(edge));
}
this.edgeComponents.Remove(edge);
diff --git a/SharpGraphProj.code-workspace b/SharpGraphProj.code-workspace
index 876a149..dda1fcf 100644
--- a/SharpGraphProj.code-workspace
+++ b/SharpGraphProj.code-workspace
@@ -4,5 +4,9 @@
"path": "."
}
],
- "settings": {}
+ "settings": {
+ "files.associations": {
+ ".fantomasignore": "ignore"
+ }
+ }
}
\ No newline at end of file