Skip to content

Commit 1f9343b

Browse files
authored
added edge contractions (#12)
* added edge contractions * fixed minor issues
1 parent 09f6e14 commit 1f9343b

File tree

9 files changed

+186
-38
lines changed

9 files changed

+186
-38
lines changed

.config/dotnet-tools.json

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,38 @@
44
"tools": {
55
"dotnet-format": {
66
"version": "5.1.250801",
7-
"commands": ["dotnet-format"],
7+
"commands": [
8+
"dotnet-format"
9+
],
810
"rollForward": false
911
},
1012
"dotnet-script": {
1113
"version": "1.4.0",
12-
"commands": ["dotnet-script"],
14+
"commands": [
15+
"dotnet-script"
16+
],
1317
"rollForward": false
1418
},
1519
"csharpier": {
1620
"version": "0.29.2",
17-
"commands": ["dotnet-csharpier"],
21+
"commands": [
22+
"dotnet-csharpier"
23+
],
1824
"rollForward": false
1925
},
2026
"husky": {
2127
"version": "0.6.1",
22-
"commands": ["husky"],
28+
"commands": [
29+
"husky"
30+
],
31+
"rollForward": false
32+
},
33+
"fantomas": {
34+
"version": "6.3.16",
35+
"commands": [
36+
"fantomas"
37+
],
2338
"rollForward": false
2439
}
2540
}
26-
}
41+
}

SharpGraph.Builder/Compiler.fs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
namespace SharpGraph.Builder
22

3-
///
4-
///
5-
///
3+
///<summary>
4+
/// Compiler module to compiel expressions representing graphs into
5+
/// graph objects.
6+
///</summary>
67
module Compiler =
78
open SharpGraph
89
open Microsoft.FSharp.Collections
@@ -121,28 +122,19 @@ module Compiler =
121122
| UnaryExp(e, op) -> HandleUnaryExp e op
122123
| BinaryOperatorExp(op, e1, e2) -> BinaryOperatorExp op e1 e2
123124

124-
///
125-
///
126-
///
125+
127126
let Parse code =
128-
System.Diagnostics.Debug.WriteLine("BEGIN PARSING")
129127

130-
match runParserOnString (pExpression .>> eof) () "Tokamak reaction stream" code with
128+
match runParserOnString (pExpression .>> eof) () "Graph compile stream" code with
131129
| Success(result, _, _) ->
132-
System.Diagnostics.Debug.WriteLine("FINISH PARSING")
133130
result
134131
| Failure(msg, _, _) ->
135-
System.Diagnostics.Debug.WriteLine("Error " + msg + "Reactor core containment failed!")
136132
failwith msg
137133

134+
///<summary>
135+
/// Compiles the given string into a Graph object.
136+
///</summary>
137+
///<param name="code">The input string to build the graph</param>
138+
///<returns>Graph object</returns>
138139
let Compile (text: string) =
139-
let result = HandleExpression(Parse text)
140-
141-
System.Console.WriteLine(
142-
"graph number of nodes "
143-
+ string (result.GetNodes().Count)
144-
+ " and edges: "
145-
+ string (result.GetEdges().Count)
146-
)
147-
148-
result
140+
HandleExpression(Parse text)

SharpGraph.Builder/SharpGraph.Builder.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PackageId>SharpGraphLib.Builder</PackageId>
44
<TargetFramework>net8.0</TargetFramework>
55
<PackageReadmeFile>README.md</PackageReadmeFile>
6-
<Version>1.0.3</Version>
6+
<Version>1.0.4</Version>
77
<Authors>Jonathan Hough</Authors>
88
<Company>Jonathan Hough</Company>
99
<GenerateDocumentationFile>true</GenerateDocumentationFile>

SharpGraph.Tests/test/CycleTest.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,6 @@
33
// Copyright Licensed under the MIT license.
44
// See LICENSE file in the samples root for full license information.
55
// </copyright>
6-
7-
using System;
8-
// <copyright file="CycleTest.cs" company="Jonathan Hough">
9-
// Copyright (C) 2023 Jonathan Hough.
10-
// Copyright Licensed under the MIT license.
11-
// See LICENSE file in the samples root for full license information.
12-
// </copyright>
136
using Xunit;
147

158
namespace SharpGraph
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// <copyright file="GraphContractionTest.cs" company="Jonathan Hough">
2+
// Copyright (C) 2023 Jonathan Hough.
3+
// Copyright Licensed under the MIT license.
4+
// See LICENSE file in the samples root for full license information.
5+
// </copyright>
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using Xunit;
10+
11+
namespace SharpGraph
12+
{
13+
public class GraphContractionTest
14+
{
15+
[Theory]
16+
[InlineData(6, "1", "2", 5, 10, 4)]
17+
[InlineData(10, "2", "6", 9, 36, 8)]
18+
public void TestContractEdgeFromComplete(
19+
uint totalNodeCount,
20+
string nodeToKeep,
21+
string nodeToRemove,
22+
int expectedNumberOfNodes,
23+
int expectedNumberOfEdges,
24+
int expectedAdjacentToKeptNode
25+
)
26+
{
27+
var edgeToRemove = new Edge(nodeToKeep, nodeToRemove);
28+
var g = GraphGenerator.CreateComplete(totalNodeCount);
29+
var h = g.ContractEdge(edgeToRemove, new Node(nodeToKeep));
30+
31+
Assert.Equal(expectedNumberOfNodes, h.GetNodes().Count);
32+
Assert.Equal(expectedNumberOfEdges, h.GetEdges().Count);
33+
Assert.Equal(expectedAdjacentToKeptNode, h.GetAdjacent(new Node(nodeToKeep)).Count);
34+
}
35+
36+
[Fact]
37+
public void TestContractionKeepsComponents()
38+
{
39+
var e1 = new Edge("1", "2");
40+
var e2 = new Edge("2", "3");
41+
var e3 = new Edge("2", "4");
42+
var e4 = new Edge("5", "8");
43+
var edges = new List<Edge> { e1, e2, e3, e4 };
44+
var g = new Graph(edges);
45+
foreach (var e in g.GetEdges())
46+
{
47+
g.AddComponent<EdgeDirection>(e);
48+
}
49+
50+
var h = g.ContractEdge(e1, new Node("1"));
51+
52+
Assert.Equal(5, h.GetNodes().Count);
53+
Assert.Equal(3, h.GetEdges().Count);
54+
Assert.Equal(2, h.GetAdjacent(new Node("1")).Count);
55+
56+
// edge that was not updated should have kept the component
57+
Assert.True(h.HasComponent<EdgeDirection>(e4));
58+
}
59+
}
60+
}

SharpGraph/SharpGraph.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFramework>net8.0</TargetFramework>
55
<PackageId>SharpGraphLib</PackageId>
66
<PackageReadmeFile>README.md</PackageReadmeFile>
7-
<Version>1.0.3</Version>
7+
<Version>1.0.4</Version>
88
<Authors>Jonathan Hough</Authors>
99
<Company>Jonathan Hough</Company>
1010
</PropertyGroup>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// <copyright file="Graph.Contraction.cs" company="Jonathan Hough">
2+
// Copyright (C) 2023 Jonathan Hough.
3+
// Copyright Licensed under the MIT license.
4+
// See LICENSE file in the samples root for full license information.
5+
// </copyright>
6+
7+
using System;
8+
using System.Collections.Generic;
9+
10+
namespace SharpGraph
11+
{
12+
public partial class Graph
13+
{
14+
/// <summary>
15+
/// Contracts the edge from the graph. This essentially removes the edge form the graph.
16+
/// Incident edges will be reassigned to connect to the "keep" node, which is one of the
17+
/// two nodes of the to-be-deleted edge.
18+
/// Edges that previously connected to the to-be-deleted node, will be deleted, and new edges to
19+
/// the to-be-kept node will be created.
20+
/// For edges not incident with the edge that is to be deleted, the edges in the returned graph will
21+
/// be copies, including any components.
22+
/// </summary>
23+
/// <param name="edge">Edge to be deleted.</param>
24+
/// <param name="keep">Node of deleted edge to keep in output graph.</param>
25+
/// <returns>Graph with edge removed.</returns>
26+
public Graph ContractEdge(Edge edge, Node keep)
27+
{
28+
if (this.GetEdges().Contains(edge) == false)
29+
{
30+
throw new Exception("Edge does not exist on this graph.");
31+
}
32+
33+
if (!edge.Nodes().Contains(keep))
34+
{
35+
throw new Exception(
36+
"Node to keep does not exist in the edge ot remove. Cannot remove edge."
37+
);
38+
}
39+
40+
var removeNode = keep == edge.To() ? edge.From() : edge.To();
41+
var incident = this.GetIncidentEdges(removeNode);
42+
var toRemove = new HashSet<Edge>();
43+
var newEdges = new HashSet<Edge>();
44+
toRemove.Add(edge);
45+
foreach (var e in incident)
46+
{
47+
if (toRemove.Contains(e))
48+
{
49+
continue;
50+
}
51+
52+
if (!e.Nodes().Contains(keep))
53+
{
54+
if (removeNode == e.To())
55+
{
56+
toRemove.Add(e);
57+
var rex = new Edge(keep, e.From());
58+
newEdges.Add(rex);
59+
}
60+
else if (removeNode == e.From())
61+
{
62+
toRemove.Add(e);
63+
var rex = new Edge(keep, e.To());
64+
newEdges.Add(rex);
65+
}
66+
}
67+
}
68+
69+
var g = this.Copy();
70+
foreach (var deadEdge in toRemove)
71+
{
72+
g.RemoveEdge(deadEdge);
73+
}
74+
75+
g.RemoveNode(removeNode);
76+
foreach (var newEdge in newEdges)
77+
{
78+
g.AddEdge(newEdge);
79+
}
80+
81+
return g;
82+
}
83+
}
84+
}

SharpGraph/src/core/Graph.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ public bool RemoveNode(Node node)
353353
if (incidentEdges != null)
354354
{
355355
this.edges.RemoveAll(e => incidentEdges.Contains(e));
356-
incidentEdges.RemoveWhere(e => incidentEdges.Contains(e));
356+
incidentEdges.RemoveWhere(e => e.Equals(e));
357357
}
358358

359359
this.nodes.Remove(node);
@@ -407,13 +407,13 @@ public bool RemoveEdge(Edge edge)
407407
var fromIncidentEdges = this.incidenceMap[f];
408408
if (fromIncidentEdges != null)
409409
{
410-
fromIncidentEdges.RemoveWhere(e => e.Equals(edge));
410+
int i = fromIncidentEdges.RemoveWhere(e => e.Equals(edge));
411411
}
412412

413413
var toIncidentEdges = this.incidenceMap[t];
414414
if (toIncidentEdges != null)
415415
{
416-
toIncidentEdges.RemoveWhere(e => e.Equals(edge));
416+
int i = toIncidentEdges.RemoveWhere(e => e.Equals(edge));
417417
}
418418

419419
this.edgeComponents.Remove(edge);

SharpGraphProj.code-workspace

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@
44
"path": "."
55
}
66
],
7-
"settings": {}
7+
"settings": {
8+
"files.associations": {
9+
".fantomasignore": "ignore"
10+
}
11+
}
812
}

0 commit comments

Comments
 (0)