From 3756285cf1fb06cbd28aa4f272ffcca18ec654c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Wed, 6 Oct 2021 23:47:56 +0200 Subject: [PATCH 01/39] Optimize the remove operations of AdjacencyGraph. See #40. --- .../Structures/Graphs/AdjacencyGraph.cs | 107 ++++++++++++++---- 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs index 7a54ca0ac..0b11a6bb7 100644 --- a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs @@ -1,7 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; using QuikGraph.Collections; @@ -311,33 +314,48 @@ protected virtual void OnVertexAdded([NotNull] TVertex vertex) VertexAdded?.Invoke(vertex); } - /// - public virtual bool RemoveVertex(TVertex vertex) +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void RemoveInEdges([NotNull, InstantHandle] Predicate shouldRemove) { - if (!ContainsVertex(vertex)) - return false; + Debug.Assert(shouldRemove != null); - // Remove out edges - IEdgeList edges = _vertexEdges[vertex]; - _vertexEdges.Remove(vertex); - - // Run over edges and remove each edge touching the vertex + // Run over edges and remove each edge touching the vertices to remove foreach (KeyValuePair> pair in _vertexEdges) { - // Collect edges to remove - foreach (TEdge edge in pair.Value.Clone()) + // Collect indexes of edges to remove + var indexesToRemove = new List(); + for (int i = 0; i < pair.Value.Count; ++i) { - if (EqualityComparer.Default.Equals(edge.Target, vertex)) + TEdge edge = pair.Value[i]; + if (shouldRemove(edge.Target)) { - pair.Value.Remove(edge); - OnEdgeRemoved(edge); - --EdgeCount; + indexesToRemove.Add(i); } } + + // Remove collected edges + for (int i = indexesToRemove.Count - 1; i >= 0; --i) + { + int indexToRemove = indexesToRemove[i]; + TEdge edgeToRemove = pair.Value[indexToRemove]; + pair.Value.RemoveAt(indexToRemove); + OnEdgeRemoved(edgeToRemove); + } + + EdgeCount -= indexesToRemove.Count; } - EdgeCount -= edges.Count; Debug.Assert(EdgeCount >= 0); + } + +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void NotifyEdgesRemoved([NotNull, ItemNotNull] IEnumerable edges) + { + Debug.Assert(edges != null); if (EdgeRemoved != null) // Lazily notify { @@ -346,7 +364,24 @@ public virtual bool RemoveVertex(TVertex vertex) OnEdgeRemoved(edge); } } + } + + /// + public virtual bool RemoveVertex(TVertex vertex) + { + if (!ContainsVertex(vertex)) + return false; + + // Remove out edges + IEdgeList edges = _vertexEdges[vertex]; + _vertexEdges.Remove(vertex); + EdgeCount -= edges.Count; + Debug.Assert(EdgeCount >= 0); + + // Remove in edges (Run over edges and remove each edge touching the vertex) + RemoveInEdges(v => EqualityComparer.Default.Equals(v, vertex)); + NotifyEdgesRemoved(edges); OnVertexRemoved(vertex); return true; @@ -372,13 +407,41 @@ public int RemoveVertexIf(VertexPredicate predicate) if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - var vertices = new VertexList(); - vertices.AddRange(Vertices.Where(vertex => predicate(vertex))); + var verticesToRemove = new VertexList(); + verticesToRemove.AddRange(Vertices.Where(vertex => predicate(vertex))); + + // Remove out edges + var verticesEdgesToRemove = new VertexEdgeDictionary(verticesToRemove.Count); + foreach (TVertex vertex in verticesToRemove) + { + verticesEdgesToRemove[vertex] = _vertexEdges[vertex]; + _vertexEdges.Remove(vertex); + } + EdgeCount -= verticesEdgesToRemove.Sum(pair => pair.Value.Count); + Debug.Assert(EdgeCount >= 0); + + // Remove in edges (Run over edges and remove each edge touching vertices to remove) + RemoveInEdges(v => verticesToRemove.Contains(v, EqualityComparer.Default)); + + NotifyEdgesRemoved(verticesEdgesToRemove.Values.SelectMany(edges => edges)); + NotifyVerticesRemoved(); + + return verticesToRemove.Count; + + #region Local function - foreach (TVertex vertex in vertices) - RemoveVertex(vertex); + void NotifyVerticesRemoved() + { + if (VertexRemoved != null) // Lazily notify + { + foreach (TVertex vertex in verticesToRemove) + { + OnVertexRemoved(vertex); + } + } + } - return vertices.Count; + #endregion } /// From fdfede359760ec6c811beef6492eeef73d6fb95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 10 Oct 2021 01:19:46 +0200 Subject: [PATCH 02/39] Various cleans and optimizations. Fix #40. --- .../Structures/Graphs/AdjacencyGraph.cs | 252 ++++++++++-------- .../Structures/Graphs/ArrayAdjacencyGraph.cs | 6 +- .../Graphs/ArrayBidirectionalGraph.cs | 8 +- .../Graphs/BidirectionalAdapterGraph.cs | 14 +- .../Structures/Graphs/BidirectionalGraph.cs | 241 +++++++++++------ .../Graphs/BidirectionalMatrixGraph.cs | 78 ++++-- .../Graphs/ClusteredAdjacencyGraph.cs | 66 +++-- .../Graphs/CompressedSparseRowGraph.cs | 11 +- .../DelegateBidirectionalIncidenceGraph.cs | 6 +- .../Graphs/DelegateVertexAndEdgeListGraph.cs | 16 +- .../Structures/Graphs/EdgeListGraph.cs | 64 +++-- .../Graphs/UndirectedBidirectionalGraph.cs | 4 +- .../Structures/Graphs/UndirectedGraph.cs | 219 ++++++++++----- .../Structures/Graphs/AdjacencyGraphTests.cs | 3 + .../Graphs/BidirectionalGraphTests.cs | 3 + .../Graphs/ClusteredAdjacencyGraphTests.cs | 11 +- .../GraphTestsBase.RemoveVertices.cs | 63 +++++ .../Structures/Graphs/UndirectedGraphTests.cs | 12 + 18 files changed, 717 insertions(+), 360 deletions(-) diff --git a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs index 0b11a6bb7..f8add4644 100644 --- a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs @@ -107,7 +107,7 @@ public AdjacencyGraph(bool allowParallelEdges, int vertexCapacity, int edgeCapac public int VertexCount => _vertexEdges.Count; [NotNull] - private readonly IVertexEdgeDictionary _vertexEdges; + private IVertexEdgeDictionary _vertexEdges; /// public virtual IEnumerable Vertices => _vertexEdges.Keys.AsEnumerable(); @@ -167,14 +167,14 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (target == null) throw new ArgumentNullException(nameof(target)); - if (_vertexEdges.TryGetValue(source, out IEdgeList edgeList) - && edgeList.Count > 0) + if (_vertexEdges.TryGetValue(source, out IEdgeList outEdges) + && outEdges.Count > 0) { - foreach (TEdge e in edgeList) + foreach (TEdge outEdge in outEdges) { - if (EqualityComparer.Default.Equals(e.Target, target)) + if (EqualityComparer.Default.Equals(outEdge.Target, target)) { - edge = e; + edge = outEdge; return true; } } @@ -218,8 +218,8 @@ public int OutDegree(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (_vertexEdges.TryGetValue(vertex, out IEdgeList edges)) - return edges.Count; + if (_vertexEdges.TryGetValue(vertex, out IEdgeList outEdges)) + return outEdges.Count; throw new VertexNotFoundException(); } @@ -240,9 +240,9 @@ public virtual bool TryGetOutEdges(TVertex vertex, out IEnumerable edges) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (_vertexEdges.TryGetValue(vertex, out IEdgeList edgeList)) + if (_vertexEdges.TryGetValue(vertex, out IEdgeList outEdges)) { - edges = edgeList.AsEnumerable(); + edges = outEdges.AsEnumerable(); return true; } @@ -271,10 +271,11 @@ public virtual bool AddVertex(TVertex vertex) if (ContainsVertex(vertex)) return false; - if (EdgeCapacity > 0) - _vertexEdges.Add(vertex, new EdgeList(EdgeCapacity)); - else - _vertexEdges.Add(vertex, new EdgeList()); + _vertexEdges.Add( + vertex, + EdgeCapacity > 0 + ? new EdgeList(EdgeCapacity) + : new EdgeList()); OnVertexAdded(vertex); @@ -294,7 +295,9 @@ public virtual int AddVertexRange(IEnumerable vertices) foreach (TVertex vertex in verticesArray) { if (AddVertex(vertex)) + { ++count; + } } return count; @@ -317,51 +320,13 @@ protected virtual void OnVertexAdded([NotNull] TVertex vertex) #if SUPPORTS_AGGRESSIVE_INLINING [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void RemoveInEdges([NotNull, InstantHandle] Predicate shouldRemove) - { - Debug.Assert(shouldRemove != null); - - // Run over edges and remove each edge touching the vertices to remove - foreach (KeyValuePair> pair in _vertexEdges) - { - // Collect indexes of edges to remove - var indexesToRemove = new List(); - for (int i = 0; i < pair.Value.Count; ++i) - { - TEdge edge = pair.Value[i]; - if (shouldRemove(edge.Target)) - { - indexesToRemove.Add(i); - } - } - - // Remove collected edges - for (int i = indexesToRemove.Count - 1; i >= 0; --i) - { - int indexToRemove = indexesToRemove[i]; - TEdge edgeToRemove = pair.Value[indexToRemove]; - pair.Value.RemoveAt(indexToRemove); - OnEdgeRemoved(edgeToRemove); - } - - EdgeCount -= indexesToRemove.Count; - } - - Debug.Assert(EdgeCount >= 0); - } - -#if SUPPORTS_AGGRESSIVE_INLINING - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - private void NotifyEdgesRemoved([NotNull, ItemNotNull] IEnumerable edges) + private void NotifyVerticesRemoved([NotNull, ItemNotNull] ICollection vertices) { - Debug.Assert(edges != null); - - if (EdgeRemoved != null) // Lazily notify + if (VertexRemoved != null) // Lazily notify { - foreach (TEdge edge in edges) + foreach (TVertex vertex in vertices) { - OnEdgeRemoved(edge); + OnVertexRemoved(vertex); } } } @@ -373,15 +338,15 @@ public virtual bool RemoveVertex(TVertex vertex) return false; // Remove out edges - IEdgeList edges = _vertexEdges[vertex]; + IEdgeList edgesToRemove = _vertexEdges[vertex]; _vertexEdges.Remove(vertex); - EdgeCount -= edges.Count; + EdgeCount -= edgesToRemove.Count; Debug.Assert(EdgeCount >= 0); // Remove in edges (Run over edges and remove each edge touching the vertex) RemoveInEdges(v => EqualityComparer.Default.Equals(v, vertex)); - NotifyEdgesRemoved(edges); + NotifyEdgesRemoved(edgesToRemove); OnVertexRemoved(vertex); return true; @@ -411,37 +376,22 @@ public int RemoveVertexIf(VertexPredicate predicate) verticesToRemove.AddRange(Vertices.Where(vertex => predicate(vertex))); // Remove out edges - var verticesEdgesToRemove = new VertexEdgeDictionary(verticesToRemove.Count); + var verticesEdgesRemoved = new VertexEdgeDictionary(verticesToRemove.Count); foreach (TVertex vertex in verticesToRemove) { - verticesEdgesToRemove[vertex] = _vertexEdges[vertex]; + verticesEdgesRemoved[vertex] = _vertexEdges[vertex]; _vertexEdges.Remove(vertex); } - EdgeCount -= verticesEdgesToRemove.Sum(pair => pair.Value.Count); + EdgeCount -= verticesEdgesRemoved.Sum(pair => pair.Value.Count); Debug.Assert(EdgeCount >= 0); // Remove in edges (Run over edges and remove each edge touching vertices to remove) RemoveInEdges(v => verticesToRemove.Contains(v, EqualityComparer.Default)); - NotifyEdgesRemoved(verticesEdgesToRemove.Values.SelectMany(edges => edges)); - NotifyVerticesRemoved(); + NotifyEdgesRemoved(verticesEdgesRemoved.Values.SelectMany(edges => edges)); + NotifyVerticesRemoved(verticesToRemove); return verticesToRemove.Count; - - #region Local function - - void NotifyVerticesRemoved() - { - if (VertexRemoved != null) // Lazily notify - { - foreach (TVertex vertex in verticesToRemove) - { - OnVertexRemoved(vertex); - } - } - } - - #endregion } /// @@ -472,7 +422,9 @@ public int AddVerticesAndEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddVerticesAndEdge(edge)) + { ++count; + } } return count; @@ -482,6 +434,10 @@ public int AddVerticesAndEdgeRange(IEnumerable edges) #region IMutableEdgeListGraph + [Pure] +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif private bool AddEdgeInternal([NotNull] TEdge edge) { Debug.Assert(edge != null); @@ -521,7 +477,9 @@ public int AddEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddEdge(edge)) + { ++count; + } } return count; @@ -541,17 +499,68 @@ protected virtual void OnEdgeAdded([NotNull] TEdge edge) EdgeAdded?.Invoke(edge); } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void RemoveInEdges([NotNull, InstantHandle] Predicate shouldRemove) + { + Debug.Assert(shouldRemove != null); + + // Run over edges and remove each edge touching the vertices to remove + foreach (KeyValuePair> pair in _vertexEdges) + { + // Collect indexes of edges to remove + var indexesToRemove = new List(); + var edgesToRemove = new List(); + for (int i = 0; i < pair.Value.Count; ++i) + { + TEdge edge = pair.Value[i]; + if (shouldRemove(edge.Target)) + { + indexesToRemove.Add(i); + edgesToRemove.Add(edge); + } + } + + // Remove collected edges + for (int i = indexesToRemove.Count - 1; i >= 0; --i) + { + pair.Value.RemoveAt(indexesToRemove[i]); + } + + EdgeCount -= indexesToRemove.Count; + Debug.Assert(EdgeCount >= 0); + NotifyEdgesRemoved(edgesToRemove); + } + } + +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void NotifyEdgesRemoved([NotNull, ItemNotNull] IEnumerable edges) + { + Debug.Assert(edges != null); + + if (EdgeRemoved != null) // Lazily notify + { + // Enumeration is only made on safe enumerable + foreach (TEdge edge in edges) + { + OnEdgeRemoved(edge); + } + } + } + /// public virtual bool RemoveEdge(TEdge edge) { if (edge == null) throw new ArgumentNullException(nameof(edge)); - if (_vertexEdges.TryGetValue(edge.Source, out IEdgeList edges) - && edges.Remove(edge)) + if (_vertexEdges.TryGetValue(edge.Source, out IEdgeList outEdges) + && outEdges.Remove(edge)) { --EdgeCount; - Debug.Assert(EdgeCount >= 0); OnEdgeRemoved(edge); @@ -575,26 +584,35 @@ protected virtual void OnEdgeRemoved([NotNull] TEdge edge) EdgeRemoved?.Invoke(edge); } - /// - public int RemoveEdgeIf(EdgePredicate predicate) +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private int RemoveEdgesInternal([NotNull] ICollection edgesToRemove) { - if (predicate is null) - throw new ArgumentNullException(nameof(predicate)); - - var edgesToRemove = new EdgeList(); - edgesToRemove.AddRange(Edges.Where(edge => predicate(edge))); - foreach (TEdge edge in edgesToRemove) { - OnEdgeRemoved(edge); _vertexEdges[edge.Source].Remove(edge); } EdgeCount -= edgesToRemove.Count; + Debug.Assert(EdgeCount >= 0); + NotifyEdgesRemoved(edgesToRemove); return edgesToRemove.Count; } + /// + public int RemoveEdgeIf(EdgePredicate predicate) + { + if (predicate is null) + throw new ArgumentNullException(nameof(predicate)); + + var edgesToRemove = new EdgeList(); + edgesToRemove.AddRange(Edges.Where(edge => predicate(edge))); + + return RemoveEdgesInternal(edgesToRemove); + } + #endregion #region IMutableIncidenceGraph @@ -604,36 +622,35 @@ public int RemoveOutEdgeIf(TVertex vertex, EdgePredicate predica { if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - if (!_vertexEdges.TryGetValue(vertex, out IEdgeList outEdges)) - return 0; - - var edgesToRemove = new EdgeList(); - edgesToRemove.AddRange(outEdges.Where(edge => predicate(edge))); - foreach (TEdge edge in edgesToRemove) - RemoveEdge(edge); + if (_vertexEdges.TryGetValue(vertex, out IEdgeList outEdges)) + { + var edgesToRemove = new EdgeList(); + edgesToRemove.AddRange(outEdges.Where(edge => predicate(edge))); + return RemoveEdgesInternal(edgesToRemove); + } - return edgesToRemove.Count; + return 0; } + #endregion + + #region IMutableIncidenceGraph + /// public void ClearOutEdges(TVertex vertex) { if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (!_vertexEdges.TryGetValue(vertex, out IEdgeList outEdges)) - return; - - int count = outEdges.Count; - if (EdgeRemoved != null) // Lazily notify + if (_vertexEdges.TryGetValue(vertex, out IEdgeList outEdges)) { - foreach (TEdge edge in outEdges) - OnEdgeRemoved(edge); + _vertexEdges[vertex] = new EdgeList(); + EdgeCount -= outEdges.Count; + Debug.Assert(EdgeCount >= 0); + NotifyEdgesRemoved(outEdges); + outEdges.Clear(); } - - outEdges.Clear(); - EdgeCount -= count; } /// @@ -649,7 +666,9 @@ public void ClearEdges([NotNull] TVertex vertex) public void TrimEdgeExcess() { foreach (IEdgeList edges in _vertexEdges.Values) + { edges.TrimExcess(); + } } #endregion @@ -659,16 +678,13 @@ public void TrimEdgeExcess() /// public void Clear() { - if (EdgeRemoved != null) // Lazily notify - { - foreach (TEdge edge in _vertexEdges.SelectMany(edges => edges.Value).Distinct()) - OnEdgeRemoved(edge); - foreach (TVertex vertex in _vertexEdges.Keys) - OnVertexRemoved(vertex); - } - - _vertexEdges.Clear(); + IVertexEdgeDictionary vertexEdges = _vertexEdges; + _vertexEdges = new VertexEdgeDictionary(); EdgeCount = 0; + + NotifyEdgesRemoved(vertexEdges.SelectMany(edges => edges.Value).Distinct()); + NotifyVerticesRemoved(vertexEdges.Keys); + vertexEdges.Clear(); } #endregion diff --git a/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs index b23b06a30..69402f29b 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -97,8 +97,8 @@ public bool ContainsEdge(TEdge edge) if (edge == null) throw new ArgumentNullException(nameof(edge)); - if (_vertexOutEdges.TryGetValue(edge.Source, out TEdge[] edges)) - return edges.Any(e => EqualityComparer.Default.Equals(e, edge)); + if (_vertexOutEdges.TryGetValue(edge.Source, out TEdge[] outEdges)) + return outEdges.Any(outEdge => EqualityComparer.Default.Equals(outEdge, edge)); return false; } diff --git a/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs index 60424c70a..bfa92057a 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -28,7 +28,7 @@ public sealed class ArrayBidirectionalGraph : IBidirectionalGrap #if SUPPORTS_SERIALIZATION [Serializable] #endif - private class InOutEdges + private sealed class InOutEdges { [NotNull, ItemNotNull] public TEdge[] OutEdges { get; } @@ -120,7 +120,7 @@ public bool ContainsEdge(TEdge edge) if (_vertexEdges.TryGetValue(edge.Source, out InOutEdges inOutEdges)) { - return inOutEdges.OutEdges.Any(e => EqualityComparer.Default.Equals(e, edge)); + return inOutEdges.OutEdges.Any(outEdge => EqualityComparer.Default.Equals(outEdge, edge)); } return false; @@ -170,7 +170,7 @@ public bool TryGetEdges(TVertex source, TVertex target, out IEnumerable e if (_vertexEdges.TryGetValue(source, out InOutEdges inOutEdges)) { - edges = inOutEdges.OutEdges.Where(edge => EqualityComparer.Default.Equals(edge.Target, target)); + edges = inOutEdges.OutEdges.Where(outEdge => EqualityComparer.Default.Equals(outEdge.Target, target)); return true; } diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs index 6557d1589..e1438efe2 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -170,8 +170,8 @@ public int InDegree(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (_inEdges.TryGetValue(vertex, out EdgeList edges)) - return edges.Count; + if (_inEdges.TryGetValue(vertex, out EdgeList inEdges)) + return inEdges.Count; throw new VertexNotFoundException(); } @@ -181,8 +181,8 @@ public IEnumerable InEdges(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (_inEdges.TryGetValue(vertex, out EdgeList edges)) - return edges.AsEnumerable(); + if (_inEdges.TryGetValue(vertex, out EdgeList inEdges)) + return inEdges.AsEnumerable(); throw new VertexNotFoundException(); } @@ -192,9 +192,9 @@ public bool TryGetInEdges(TVertex vertex, out IEnumerable edges) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (_inEdges.TryGetValue(vertex, out EdgeList edgeList)) + if (_inEdges.TryGetValue(vertex, out EdgeList inEdges)) { - edges = edgeList.AsEnumerable(); + edges = inEdges.AsEnumerable(); return true; } diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs index 04dc8852d..06175c65d 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs @@ -1,7 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; using QuikGraph.Collections; @@ -174,13 +177,13 @@ public int OutDegree(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (_vertexOutEdges.TryGetValue(vertex, out IEdgeList edges)) - return edges.Count; + if (_vertexOutEdges.TryGetValue(vertex, out IEdgeList outEdges)) + return outEdges.Count; throw new VertexNotFoundException(); } [NotNull] - private readonly IVertexEdgeDictionary _vertexOutEdges; + private IVertexEdgeDictionary _vertexOutEdges; /// public IEnumerable OutEdges(TVertex vertex) @@ -232,11 +235,11 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (_vertexOutEdges.TryGetValue(source, out IEdgeList outEdges) && outEdges.Count > 0) { - foreach (TEdge e in outEdges) + foreach (TEdge outEdge in outEdges) { - if (EqualityComparer.Default.Equals(e.Target, target)) + if (EqualityComparer.Default.Equals(outEdge.Target, target)) { - edge = e; + edge = outEdge; return true; } } @@ -286,7 +289,7 @@ public int InDegree(TVertex vertex) } [NotNull] - private readonly IVertexEdgeDictionary _vertexInEdges; + private IVertexEdgeDictionary _vertexInEdges; /// public IEnumerable InEdges(TVertex vertex) @@ -336,17 +339,16 @@ public int Degree(TVertex vertex) /// public void Clear() { - if (EdgeRemoved != null) // Lazily notify - { - foreach (TEdge edge in _vertexOutEdges.SelectMany(edges => edges.Value).Distinct()) - OnEdgeRemoved(edge); - foreach (TVertex vertex in _vertexOutEdges.Keys) - OnVertexRemoved(vertex); - } - - _vertexOutEdges.Clear(); - _vertexInEdges.Clear(); + IVertexEdgeDictionary vertexOutEdges = _vertexOutEdges; + _vertexOutEdges = new VertexEdgeDictionary(); + IVertexEdgeDictionary vertexInEdges = _vertexInEdges; + _vertexInEdges = new VertexEdgeDictionary(); EdgeCount = 0; + + NotifyEdgesRemoved(vertexOutEdges.SelectMany(edges => edges.Value).Distinct()); + NotifyVerticesRemoved(vertexOutEdges.Keys); + vertexOutEdges.Clear(); + vertexInEdges.Clear(); } #endregion @@ -388,7 +390,9 @@ public virtual int AddVertexRange(IEnumerable vertices) foreach (TVertex vertex in verticesArray) { if (AddVertex(vertex)) + { ++count; + } } return count; @@ -408,37 +412,55 @@ protected virtual void OnVertexAdded([NotNull] TVertex vertex) VertexAdded?.Invoke(vertex); } - /// - public virtual bool RemoveVertex(TVertex vertex) +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void NotifyVerticesRemoved([NotNull, ItemNotNull] ICollection vertices) { - if (!ContainsVertex(vertex)) - return false; - - // Collect edges to remove - var edgesToRemove = new EdgeList(); - foreach (TEdge outEdge in OutEdges(vertex)) + if (VertexRemoved != null) // Lazily notify { - _vertexInEdges[outEdge.Target].Remove(outEdge); - edgesToRemove.Add(outEdge); + foreach (TVertex vertex in vertices) + { + OnVertexRemoved(vertex); + } } + } - foreach (TEdge inEdge in InEdges(vertex)) + [NotNull, ItemNotNull] +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private IEnumerable RemoveInOutEdges([NotNull] TVertex vertex) + { + IEdgeList outEdges = _vertexOutEdges[vertex]; + _vertexOutEdges.Remove(vertex); + foreach (TEdge outEdge in outEdges) { - // Might already have been removed - if (_vertexOutEdges[inEdge.Source].Remove(inEdge)) - edgesToRemove.Add(inEdge); + _vertexInEdges[outEdge.Target].Remove(outEdge); } - // Notify users - if (EdgeRemoved != null) + IEdgeList inEdges = _vertexInEdges[vertex]; + _vertexInEdges.Remove(vertex); + foreach (TEdge inEdge in inEdges) { - foreach (TEdge edge in edgesToRemove) - OnEdgeRemoved(edge); + _vertexOutEdges[inEdge.Source].Remove(inEdge); } - _vertexOutEdges.Remove(vertex); - _vertexInEdges.Remove(vertex); - EdgeCount -= edgesToRemove.Count; + EdgeCount -= outEdges.Count + inEdges.Count; + Debug.Assert(EdgeCount >= 0); + + return outEdges.Concat(inEdges); + } + + /// + public virtual bool RemoveVertex(TVertex vertex) + { + if (!ContainsVertex(vertex)) + return false; + + IEnumerable inOutEdges = RemoveInOutEdges(vertex); + + NotifyEdgesRemoved(inOutEdges); OnVertexRemoved(vertex); return true; @@ -467,8 +489,12 @@ public int RemoveVertexIf(VertexPredicate predicate) var verticesToRemove = new VertexList(); verticesToRemove.AddRange(Vertices.Where(vertex => predicate(vertex))); - foreach (TVertex vertex in verticesToRemove) - RemoveVertex(vertex); + IEnumerable edgesRemoved = verticesToRemove.Aggregate( + Enumerable.Empty(), + (current, vertex) => current.Concat(RemoveInOutEdges(vertex))); + + NotifyEdgesRemoved(edgesRemoved); + NotifyVerticesRemoved(verticesToRemove); return verticesToRemove.Count; } @@ -477,6 +503,9 @@ public int RemoveVertexIf(VertexPredicate predicate) #region IMutableEdgeListGraph +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif private bool AddEdgeInternal([NotNull] TEdge edge) { Debug.Assert(edge != null); @@ -517,7 +546,9 @@ public int AddEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddEdge(edge)) + { ++count; + } } return count; @@ -537,6 +568,23 @@ protected virtual void OnEdgeAdded([NotNull] TEdge edge) EdgeAdded?.Invoke(edge); } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void NotifyEdgesRemoved([NotNull, ItemNotNull] IEnumerable edges) + { + Debug.Assert(edges != null); + + if (EdgeRemoved != null) // Lazily notify + { + // Enumeration is only made on safe enumerable + foreach (TEdge edge in edges) + { + OnEdgeRemoved(edge); + } + } + } + /// public virtual bool RemoveEdge(TEdge edge) { @@ -548,7 +596,6 @@ public virtual bool RemoveEdge(TEdge edge) { _vertexInEdges[edge.Target].Remove(edge); --EdgeCount; - Debug.Assert(EdgeCount >= 0); OnEdgeRemoved(edge); @@ -572,6 +619,24 @@ protected virtual void OnEdgeRemoved([NotNull] TEdge edge) EdgeRemoved?.Invoke(edge); } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private int RemoveEdgesInternal([NotNull] ICollection edgesToRemove) + { + foreach (TEdge edge in edgesToRemove) + { + _vertexOutEdges[edge.Source].Remove(edge); + _vertexInEdges[edge.Target].Remove(edge); + } + + EdgeCount -= edgesToRemove.Count; + Debug.Assert(EdgeCount >= 0); + NotifyEdgesRemoved(edgesToRemove); + + return edgesToRemove.Count; + } + /// public int RemoveEdgeIf(EdgePredicate predicate) { @@ -581,10 +646,7 @@ public int RemoveEdgeIf(EdgePredicate predicate) var edgesToRemove = new EdgeList(); edgesToRemove.AddRange(Edges.Where(edge => predicate(edge))); - foreach (TEdge edge in edgesToRemove) - RemoveEdge(edge); - - return edgesToRemove.Count; + return RemoveEdgesInternal(edgesToRemove); } #endregion @@ -615,7 +677,9 @@ public int AddVerticesAndEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddVerticesAndEdge(edge)) + { ++count; + } } return count; @@ -630,16 +694,15 @@ public int RemoveOutEdgeIf(TVertex vertex, EdgePredicate predica { if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - if (!_vertexOutEdges.TryGetValue(vertex, out IEdgeList outEdges)) - return 0; - - var edgesToRemove = new EdgeList(); - edgesToRemove.AddRange(outEdges.Where(edge => predicate(edge))); - foreach (TEdge edge in edgesToRemove) - RemoveEdge(edge); + if (_vertexOutEdges.TryGetValue(vertex, out IEdgeList outEdges)) + { + var edgesToRemove = new EdgeList(); + edgesToRemove.AddRange(outEdges.Where(edge => predicate(edge))); + return RemoveEdgesInternal(edgesToRemove); + } - return edgesToRemove.Count; + return 0; } /// @@ -648,26 +711,33 @@ public void ClearOutEdges(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (!_vertexOutEdges.TryGetValue(vertex, out IEdgeList outEdges)) - return; - - foreach (TEdge edge in outEdges) + if (_vertexOutEdges.TryGetValue(vertex, out IEdgeList outEdges)) { - _vertexInEdges[edge.Target].Remove(edge); - OnEdgeRemoved(edge); - } + _vertexOutEdges[vertex] = new EdgeList(); + foreach (TEdge outEdge in outEdges) + { + _vertexInEdges[outEdge.Target].Remove(outEdge); + } - EdgeCount -= outEdges.Count; - outEdges.Clear(); + EdgeCount -= outEdges.Count; + Debug.Assert(EdgeCount >= 0); + NotifyEdgesRemoved(outEdges); + outEdges.Clear(); + } } /// public void TrimEdgeExcess() { - foreach (IEdgeList edges in _vertexInEdges.Values) - edges.TrimExcess(); - foreach (IEdgeList edges in _vertexOutEdges.Values) - edges.TrimExcess(); + foreach (IEdgeList inEdges in _vertexInEdges.Values) + { + inEdges.TrimExcess(); + } + + foreach (IEdgeList outEdges in _vertexOutEdges.Values) + { + outEdges.TrimExcess(); + } } #endregion @@ -679,16 +749,15 @@ public int RemoveInEdgeIf(TVertex vertex, EdgePredicate predicat { if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - if (!_vertexInEdges.TryGetValue(vertex, out IEdgeList inEdges)) - return 0; - - var edgesToRemove = new EdgeList(); - edgesToRemove.AddRange(inEdges.Where(edge => predicate(edge))); - foreach (TEdge edge in edgesToRemove) - RemoveEdge(edge); + if (_vertexInEdges.TryGetValue(vertex, out IEdgeList inEdges)) + { + var edgesToRemove = new EdgeList(); + edgesToRemove.AddRange(inEdges.Where(edge => predicate(edge))); + return RemoveEdgesInternal(edgesToRemove); + } - return edgesToRemove.Count; + return 0; } /// @@ -697,17 +766,19 @@ public void ClearInEdges(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (!_vertexInEdges.TryGetValue(vertex, out IEdgeList inEdges)) - return; - - foreach (TEdge edge in inEdges) + if (_vertexInEdges.TryGetValue(vertex, out IEdgeList inEdges)) { - _vertexOutEdges[edge.Source].Remove(edge); - OnEdgeRemoved(edge); - } + _vertexInEdges[vertex] = new EdgeList(); + foreach (TEdge inEdge in inEdges) + { + _vertexOutEdges[inEdge.Source].Remove(inEdge); + } - EdgeCount -= inEdges.Count; - inEdges.Clear(); + EdgeCount -= inEdges.Count; + Debug.Assert(EdgeCount >= 0); + NotifyEdgesRemoved(inEdges); + inEdges.Clear(); + } } /// @@ -778,7 +849,9 @@ public void MergeVerticesIf( // Applying merge recursively foreach (TVertex vertex in mergeVertices) + { MergeVertex(vertex, edgeFactory); + } } #region ICloneable diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs index 5f0d330a0..851e21a8a 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs @@ -1,7 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; namespace QuikGraph @@ -200,7 +203,9 @@ public int OutDegree(int vertex) for (int j = 0; j < VertexCount; ++j) { if (_edges[vertex, j] != null) + { ++count; + } } return count; @@ -279,7 +284,9 @@ public int InDegree(int vertex) for (int i = 0; i < VertexCount; ++i) { if (_edges[i, vertex] != null) + { ++count; + } } return count; @@ -344,19 +351,20 @@ public int Degree(int vertex) /// public void Clear() { + EdgeCount = 0; for (int i = 0; i < VertexCount; ++i) { for (int j = 0; j < VertexCount; ++j) { TEdge edge = _edges[i, j]; - _edges[i, j] = default(TEdge); + _edges[i, j] = null; if (edge != null) + { OnEdgeRemoved(edge); + } } } - - EdgeCount = 0; } #endregion @@ -383,7 +391,7 @@ public int RemoveInEdgeIf(int vertex, [NotNull, InstantHandle] EdgePredicate @@ -514,7 +533,9 @@ public int AddEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddEdge(edge)) + { ++count; + } } return count; @@ -534,6 +555,20 @@ protected virtual void OnEdgeAdded([NotNull] TEdge edge) EdgeAdded?.Invoke(edge); } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void RemoveEdgeInternal([NotNull] TEdge edge) + { + Debug.Assert(edge != null); + Debug.Assert(_edges[edge.Source, edge.Target] != null); + + _edges[edge.Source, edge.Target] = null; + --EdgeCount; + Debug.Assert(EdgeCount >= 0); + OnEdgeRemoved(edge); + } + /// public bool RemoveEdge(TEdge edge) { @@ -541,18 +576,13 @@ public bool RemoveEdge(TEdge edge) throw new ArgumentNullException(nameof(edge)); if (!AreInGraph(edge.Source, edge.Target)) return false; - TEdge edgeToRemove = _edges[edge.Source, edge.Target]; - if (edgeToRemove != null) - { - _edges[edge.Source, edge.Target] = null; + if (edgeToRemove is null) + return false; - --EdgeCount; - OnEdgeRemoved(edgeToRemove); - return true; - } + RemoveEdgeInternal(edgeToRemove); - return false; + return true; } /// diff --git a/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs index 4f132ec28..10c0cc7c9 100644 --- a/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs @@ -3,7 +3,11 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; +using QuikGraph.Collections; namespace QuikGraph { @@ -258,7 +262,9 @@ public virtual int AddVertexRange([NotNull, ItemNotNull] IEnumerable ve foreach (TVertex vertex in verticesArray) { if (AddVertex(vertex)) + { ++count; + } } return count; @@ -282,6 +288,18 @@ private void RemoveChildVertex([NotNull] TVertex vertex) } } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void RemoveVertexInternal([NotNull] TVertex vertex) + { + Debug.Assert(vertex != null); + + RemoveChildVertex(vertex); + Wrapped.RemoveVertex(vertex); + Parent?.RemoveVertex(vertex); + } + /// /// Removes the given vertex from this graph. /// @@ -295,9 +313,7 @@ public virtual bool RemoveVertex([NotNull] TVertex vertex) if (!Wrapped.ContainsVertex(vertex)) return false; - RemoveChildVertex(vertex); - Wrapped.RemoveVertex(vertex); - Parent?.RemoveVertex(vertex); + RemoveVertexInternal(vertex); return true; } @@ -312,14 +328,15 @@ public int RemoveVertexIf([NotNull, InstantHandle] VertexPredicate pred if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - TVertex[] verticesToRemove = Vertices - .Where(vertex => predicate(vertex)) - .ToArray(); + var verticesToRemove = new VertexList(); + verticesToRemove.AddRange(Vertices.Where(vertex => predicate(vertex))); foreach (TVertex vertex in verticesToRemove) - RemoveVertex(vertex); + { + RemoveVertexInternal(vertex); + } - return verticesToRemove.Length; + return verticesToRemove.Count; } /// @@ -354,7 +371,9 @@ public int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edg foreach (TEdge edge in edgesArray) { if (AddVerticesAndEdge(edge)) + { ++count; + } } return count; @@ -371,7 +390,9 @@ public virtual bool AddEdge([NotNull] TEdge edge) throw new ArgumentNullException(nameof(edge)); if (Parent != null && !Parent.ContainsEdge(edge)) + { Parent.AddEdge(edge); + } return Wrapped.AddEdge(edge); } @@ -392,7 +413,9 @@ public int AddEdgeRange([NotNull, ItemNotNull] IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddEdge(edge)) + { ++count; + } } return count; @@ -412,6 +435,18 @@ private void RemoveChildEdge([NotNull] TEdge edge) } } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void RemoveEdgeInternal([NotNull] TEdge edge) + { + Debug.Assert(edge != null); + + RemoveChildEdge(edge); + Wrapped.RemoveEdge(edge); + Parent?.RemoveEdge(edge); + } + /// /// Removes the from this graph. /// @@ -425,9 +460,7 @@ public virtual bool RemoveEdge([NotNull] TEdge edge) if (!Wrapped.ContainsEdge(edge)) return false; - RemoveChildEdge(edge); - Wrapped.RemoveEdge(edge); - Parent?.RemoveEdge(edge); + RemoveEdgeInternal(edge); return true; } @@ -442,14 +475,15 @@ public int RemoveEdgeIf([NotNull, InstantHandle] EdgePredicate p if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - var edgesToRemove = Wrapped.Edges - .Where(edge => predicate(edge)) - .ToArray(); + var edgesToRemove = new EdgeList(); + edgesToRemove.AddRange(Edges.Where(edge => predicate(edge))); foreach (TEdge edge in edgesToRemove) - RemoveEdge(edge); + { + RemoveEdgeInternal(edge); + } - return edgesToRemove.Length; + return edgesToRemove.Count; } /// diff --git a/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs b/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs index 3d139207b..2a8ed4203 100644 --- a/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs +++ b/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs @@ -1,6 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; namespace QuikGraph @@ -108,7 +112,7 @@ public static CompressedSparseRowGraph FromGraph( public int VertexCount => _outEdgeStartRanges.Count; /// - public IEnumerable Vertices => _outEdgeStartRanges.Keys; + public IEnumerable Vertices => _outEdgeStartRanges.Keys.AsEnumerable(); /// public bool ContainsVertex(TVertex vertex) @@ -258,6 +262,9 @@ public IEnumerable> OutEdges(TVertex vertex) [Pure] [NotNull] +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif private IEnumerable> OutEdgesIterator([NotNull] TVertex vertex) { Debug.Assert(vertex != null); diff --git a/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs index cc8e1b75d..93458cbff 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -58,8 +58,8 @@ public IEnumerable InEdges(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (_tryGetInEdgesFunc(vertex, out IEnumerable result)) - return result; + if (_tryGetInEdgesFunc(vertex, out IEnumerable inEdges)) + return inEdges; throw new VertexNotFoundException(); } diff --git a/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs index 0253cbe02..0bcbdcb45 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -69,7 +69,7 @@ public bool IsEdgesEmpty /// public virtual IEnumerable Edges => _vertices.SelectMany( - vertex => OutEdges(vertex).Where(edge => EqualityComparer.Default.Equals(edge.Source, vertex))); + vertex => OutEdges(vertex).Where(outEdge => EqualityComparer.Default.Equals(outEdge.Source, vertex))); /// public bool ContainsEdge(TEdge edge) @@ -77,8 +77,8 @@ public bool ContainsEdge(TEdge edge) if (edge == null) throw new ArgumentNullException(nameof(edge)); - if (TryGetOutEdges(edge.Source, out IEnumerable edges)) - return edges.Any(e => EqualityComparer.Default.Equals(e, edge)); + if (TryGetOutEdges(edge.Source, out IEnumerable outEdges)) + return outEdges.Any(outEdge => EqualityComparer.Default.Equals(outEdge, edge)); return false; } @@ -143,7 +143,7 @@ internal override IEnumerable OutEdgesInternal(TVertex vertex) { if (!ContainsVertexInternal(vertex)) throw new VertexNotFoundException(); - return base.OutEdgesInternal(vertex).Where(edge => FilterEdges(edge, vertex)); + return base.OutEdgesInternal(vertex).Where(outEdge => FilterEdges(outEdge, vertex)); } /// @@ -157,11 +157,11 @@ internal override bool TryGetOutEdgesInternal(TVertex vertex, out IEnumerable unfilteredEdges); + base.TryGetOutEdgesInternal(vertex, out IEnumerable unfilteredOutEdges); - edges = unfilteredEdges is null + edges = unfilteredOutEdges is null ? Enumerable.Empty() - : unfilteredEdges.Where(edge => FilterEdges(edge, vertex)); + : unfilteredOutEdges.Where(outEdge => FilterEdges(outEdge, vertex)); return true; } diff --git a/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs b/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs index d5323777b..262720fe6 100644 --- a/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs +++ b/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs @@ -1,7 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; using QuikGraph.Collections; @@ -62,6 +65,8 @@ public EdgeListGraph(bool isDirected, bool allowParallelEdges) /// public IEnumerable Vertices => GetVertices().AsEnumerable(); + [Pure] + [NotNull, ItemNotNull] private HashSet GetVertices() { var vertices = new HashSet(); @@ -89,8 +94,7 @@ public bool ContainsVertex(TVertex vertex) #region IEdgeSet [NotNull] - private readonly EdgeEdgeDictionary _edges - = new EdgeEdgeDictionary(); + private EdgeEdgeDictionary _edges = new EdgeEdgeDictionary(); /// public bool IsEdgesEmpty => _edges.Count == 0; @@ -99,7 +103,7 @@ private readonly EdgeEdgeDictionary _edges public int EdgeCount => _edges.Count; /// - public IEnumerable Edges => _edges.Keys; + public IEnumerable Edges => _edges.Keys.AsEnumerable(); /// public bool ContainsEdge(TEdge edge) @@ -110,6 +114,7 @@ public bool ContainsEdge(TEdge edge) return _edges.ContainsKey(edge); } + [Pure] private bool ContainsEdge(TVertex source, TVertex target) { Debug.Assert(source != null); @@ -152,7 +157,9 @@ public int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edg foreach (TEdge edge in edgesArray) { if (AddVerticesAndEdge(edge)) + { ++count; + } } return count; @@ -191,7 +198,9 @@ public int AddEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddEdge(edge)) + { ++count; + } } return count; @@ -211,17 +220,20 @@ protected virtual void OnEdgeAdded([NotNull] TEdge edge) EdgeAdded?.Invoke(edge); } - private bool RemoveEdgeInternal([NotNull] TEdge edge) +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void NotifyEdgesRemoved([NotNull, ItemNotNull] ICollection edges) { - Debug.Assert(edge != null); + Debug.Assert(edges != null); - if (_edges.Remove(edge)) + if (EdgeRemoved != null) // Lazily notify { - OnEdgeRemoved(edge); - return true; + foreach (TEdge edge in edges) + { + OnEdgeRemoved(edge); + } } - - return false; } /// @@ -230,7 +242,13 @@ public bool RemoveEdge(TEdge edge) if (edge == null) throw new ArgumentNullException(nameof(edge)); - return RemoveEdgeInternal(edge); + if (_edges.Remove(edge)) + { + OnEdgeRemoved(edge); + return true; + } + + return false; } /// @@ -253,11 +271,17 @@ public int RemoveEdgeIf(EdgePredicate predicate) if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - TEdge[] edgesToRemove = Edges.Where(edge => predicate(edge)).ToArray(); + var edgesToRemove = new EdgeList(); + edgesToRemove.AddRange(Edges.Where(edge => predicate(edge))); foreach (TEdge edge in edgesToRemove) - RemoveEdgeInternal(edge); - return edgesToRemove.Length; + { + _edges.Remove(edge); + } + + NotifyEdgesRemoved(edgesToRemove); + + return edgesToRemove.Count; } #endregion @@ -265,11 +289,11 @@ public int RemoveEdgeIf(EdgePredicate predicate) /// public void Clear() { - EdgeEdgeDictionary edges = _edges.Clone(); - _edges.Clear(); - - foreach (TEdge edge in edges.Keys) - OnEdgeRemoved(edge); + EdgeEdgeDictionary edges = _edges; + _edges = new EdgeEdgeDictionary(); + + NotifyEdgesRemoved(edges.Keys); + edges.Clear(); } #region ICloneable diff --git a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs index c5fbb72fd..056bb932b 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -140,7 +140,7 @@ public IEnumerable AdjacentEdges(TVertex vertex) .Concat( OriginalGraph.InEdges(vertex) // We skip self edges here since - // We already did those in the out-edge run + // We already got them out-edge run .Where(inEdge => !inEdge.IsSelfEdge())); } diff --git a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs index d6ddfb27a..adb4edf04 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs @@ -1,10 +1,13 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; #if !SUPPORTS_TYPE_FULL_FEATURES using System.Reflection; #endif +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif #if SUPPORTS_SERIALIZATION && NETSTANDARD2_0 using System.Runtime.Serialization; using System.Security.Permissions; @@ -33,7 +36,7 @@ public class UndirectedGraph : IMutableUndirectedGraph { [NotNull] - private readonly IVertexEdgeDictionary _adjacentEdges = + private IVertexEdgeDictionary _adjacentEdges = new VertexEdgeDictionary(); /// @@ -123,7 +126,7 @@ public IEnumerable AdjacentVertices([NotNull] TVertex vertex) adjacentVertices.Remove(vertex); - return adjacentVertices; + return adjacentVertices.AsEnumerable(); } #region IGraph @@ -167,7 +170,7 @@ public bool ContainsVertex(TVertex vertex) public int EdgeCount { get; private set; } [NotNull, ItemNotNull] - private readonly IList _edges = new List(); + private IList _edges = new List(); /// public IEnumerable Edges => _edges.AsEnumerable(); @@ -196,6 +199,7 @@ public bool ContainsEdge(TVertex source, TVertex target) return TryGetEdge(source, target, out _); } + [Pure] private bool ContainsEdgeBetweenVertices([NotNull, ItemNotNull] IEnumerable edges, [NotNull] TEdge edge) { Debug.Assert(edges != null); @@ -265,18 +269,15 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) _reorder(source, target, out source, out target); - if (!_adjacentEdges.TryGetValue(source, out IEdgeList adjacentEdges)) - { - edge = default(TEdge); - return false; - } - - foreach (TEdge adjacentEdge in adjacentEdges) + if (_adjacentEdges.TryGetValue(source, out IEdgeList adjacentEdges)) { - if (EdgeEqualityComparer(adjacentEdge, source, target)) + foreach (TEdge adjacentEdge in adjacentEdges) { - edge = adjacentEdge; - return true; + if (EdgeEqualityComparer(adjacentEdge, source, target)) + { + edge = adjacentEdge; + return true; + } } } @@ -302,17 +303,16 @@ public void TrimEdgeExcess() /// public void Clear() { - if (EdgeRemoved != null) // Lazily notify - { - foreach (TEdge edge in _edges) - OnEdgeRemoved(edge); - foreach (TVertex vertex in _adjacentEdges.Keys) - OnVertexRemoved(vertex); - } - - _edges.Clear(); - _adjacentEdges.Clear(); + IList edges = _edges; + _edges = new List(); + IVertexEdgeDictionary adjacentEdges = _adjacentEdges; + _adjacentEdges = new VertexEdgeDictionary(); EdgeCount = 0; + + NotifyEdgesRemoved(edges); + NotifyVerticesRemoved(adjacentEdges.Keys); + edges.Clear(); + adjacentEdges.Clear(); } #endregion @@ -333,6 +333,23 @@ protected virtual void OnVertexAdded([NotNull] TVertex vertex) VertexAdded?.Invoke(vertex); } + /// + public bool AddVertex(TVertex vertex) + { + if (ContainsVertex(vertex)) + return false; + + _adjacentEdges.Add( + vertex, + EdgeCapacity > 0 + ? new EdgeList(EdgeCapacity) + : new EdgeList()); + + OnVertexAdded(vertex); + + return true; + } + /// public int AddVertexRange(IEnumerable vertices) { @@ -346,28 +363,15 @@ public int AddVertexRange(IEnumerable vertices) foreach (TVertex vertex in verticesArray) { if (AddVertex(vertex)) + { ++count; + } } return count; } - /// - public bool AddVertex(TVertex vertex) - { - if (ContainsVertex(vertex)) - return false; - - var edges = EdgeCapacity < 0 - ? new EdgeList() - : new EdgeList(EdgeCapacity); - - _adjacentEdges.Add(vertex, edges); - OnVertexAdded(vertex); - - return true; - } - + [Pure] [NotNull] private IEdgeList AddAndReturnEdges([NotNull] TVertex vertex) { @@ -375,9 +379,9 @@ private IEdgeList AddAndReturnEdges([NotNull] TVertex vertex) if (!_adjacentEdges.TryGetValue(vertex, out IEdgeList edges)) { - _adjacentEdges[vertex] = edges = EdgeCapacity < 0 - ? new EdgeList() - : new EdgeList(EdgeCapacity); + _adjacentEdges[vertex] = edges = EdgeCapacity > 0 + ? new EdgeList(EdgeCapacity) + : new EdgeList(); OnVertexAdded(vertex); } @@ -399,6 +403,20 @@ protected virtual void OnVertexRemoved([NotNull] TVertex vertex) VertexRemoved?.Invoke(vertex); } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void NotifyVerticesRemoved([NotNull, ItemNotNull] IEnumerable vertices) + { + if (VertexRemoved != null) // Lazily notify + { + foreach (TVertex vertex in vertices) + { + OnVertexRemoved(vertex); + } + } + } + /// public bool RemoveVertex(TVertex vertex) { @@ -406,7 +424,9 @@ public bool RemoveVertex(TVertex vertex) bool removed = _adjacentEdges.Remove(vertex); if (removed) + { OnVertexRemoved(vertex); + } return removed; } @@ -417,14 +437,18 @@ public int RemoveVertexIf(VertexPredicate predicate) if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - TVertex[] verticesToRemove = Vertices - .Where(vertex => predicate(vertex)) - .ToArray(); + var verticesToRemove = new VertexList(); + verticesToRemove.AddRange(Vertices.Where(vertex => predicate(vertex))); foreach (TVertex vertex in verticesToRemove) - RemoveVertex(vertex); + { + ClearAdjacentEdges(vertex); + _adjacentEdges.Remove(vertex); + } - return verticesToRemove.Length; + NotifyVerticesRemoved(verticesToRemove); + + return verticesToRemove.Count; } #endregion @@ -436,14 +460,15 @@ public int RemoveAdjacentEdgeIf(TVertex vertex, EdgePredicate pr { if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - if (!_adjacentEdges.TryGetValue(vertex, out IEdgeList adjacentEdges)) - return 0; - var edges = new List(); - edges.AddRange(adjacentEdges.Where(edge => predicate(edge))); + if (_adjacentEdges.TryGetValue(vertex, out IEdgeList adjacentEdges)) + { + var edgesToRemove = new VertexList(); + edgesToRemove.AddRange(adjacentEdges.Where(edge => predicate(edge))); + return RemoveEdgesInternal(edgesToRemove); + } - RemoveEdges(edges); - return edges.Count; + return 0; } /// @@ -452,22 +477,29 @@ public void ClearAdjacentEdges(TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - if (!_adjacentEdges.TryGetValue(vertex, out IEdgeList adjacentEdges)) - return; + if (_adjacentEdges.TryGetValue(vertex, out IEdgeList adjacentEdges)) + { + IEdgeList edgesToRemove = adjacentEdges.Clone(); + adjacentEdges.Clear(); + EdgeCount -= edgesToRemove.Count; + Debug.Assert(EdgeCount >= 0); - IEdgeList edgesToRemove = adjacentEdges.Clone(); - EdgeCount -= edgesToRemove.Count; + foreach (TEdge edge in edgesToRemove) + { + if (_adjacentEdges.TryGetValue(edge.Target, out adjacentEdges)) + { + adjacentEdges.Remove(edge); + } - foreach (TEdge edge in edgesToRemove) - { - if (_adjacentEdges.TryGetValue(edge.Target, out adjacentEdges)) - adjacentEdges.Remove(edge); + if (_adjacentEdges.TryGetValue(edge.Source, out adjacentEdges)) + { + adjacentEdges.Remove(edge); + } - if (_adjacentEdges.TryGetValue(edge.Source, out adjacentEdges)) - adjacentEdges.Remove(edge); + _edges.Remove(edge); + } - _edges.Remove(edge); - OnEdgeRemoved(edge); + NotifyEdgesRemoved(edgesToRemove); } } @@ -499,7 +531,9 @@ public bool AddVerticesAndEdge(TEdge edge) _edges.Add(edge); sourceEdges.Add(edge); if (!edge.IsSelfEdge()) + { targetEdges.Add(edge); + } ++EdgeCount; OnEdgeAdded(edge); @@ -520,7 +554,9 @@ public int AddVerticesAndEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddVerticesAndEdge(edge)) + { ++count; + } } return count; @@ -566,7 +602,9 @@ public int AddEdgeRange(IEnumerable edges) foreach (TEdge edge in edgesArray) { if (AddEdge(edge)) + { ++count; + } } return count; @@ -586,6 +624,22 @@ protected virtual void OnEdgeAdded([NotNull] TEdge edge) EdgeAdded?.Invoke(edge); } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void NotifyEdgesRemoved([NotNull, ItemNotNull] ICollection edges) + { + Debug.Assert(edges != null); + + if (EdgeRemoved != null) // Lazily notify + { + foreach (TEdge edge in edges) + { + OnEdgeRemoved(edge); + } + } + } + /// public bool RemoveEdge(TEdge edge) { @@ -598,9 +652,10 @@ public bool RemoveEdge(TEdge edge) _edges.Remove(edge); if (!edge.IsSelfEdge()) + { _adjacentEdges[edge.Target].Remove(edge); + } --EdgeCount; - Debug.Assert(EdgeCount >= 0); OnEdgeRemoved(edge); @@ -630,10 +685,36 @@ public int RemoveEdgeIf(EdgePredicate predicate) if (predicate is null) throw new ArgumentNullException(nameof(predicate)); - return RemoveEdges( + return RemoveEdgesInternal( Edges.Where(edge => predicate(edge)).ToArray()); } +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private int RemoveEdgesInternal([NotNull, ItemNotNull] ICollection edgesToRemove) + { + foreach (TEdge edge in edgesToRemove) + { + if (_adjacentEdges.TryGetValue(edge.Source, out IEdgeList adjacentEdges) + && adjacentEdges.Remove(edge)) + { + _edges.Remove(edge); + + if (!edge.IsSelfEdge()) + { + _adjacentEdges[edge.Target].Remove(edge); + } + } + } + + EdgeCount -= edgesToRemove.Count; + Debug.Assert(EdgeCount >= 0); + NotifyEdgesRemoved(edgesToRemove); + + return edgesToRemove.Count; + } + /// /// Removes the given set of edges. /// @@ -651,7 +732,9 @@ public int RemoveEdges([NotNull, ItemNotNull] IEnumerable edges) foreach (TEdge edge in edgesArray) { if (RemoveEdge(edge)) + { ++count; + } } return count; diff --git a/tests/QuikGraph.Tests/Structures/Graphs/AdjacencyGraphTests.cs b/tests/QuikGraph.Tests/Structures/Graphs/AdjacencyGraphTests.cs index 15a2b330f..0d571306b 100644 --- a/tests/QuikGraph.Tests/Structures/Graphs/AdjacencyGraphTests.cs +++ b/tests/QuikGraph.Tests/Structures/Graphs/AdjacencyGraphTests.cs @@ -341,6 +341,9 @@ public void RemoveVertexIf() { var graph = new AdjacencyGraph>(); RemoveVertexIf_Test(graph); + + graph = new AdjacencyGraph>(); + RemoveVertexIf_Test2(graph); } [Test] diff --git a/tests/QuikGraph.Tests/Structures/Graphs/BidirectionalGraphTests.cs b/tests/QuikGraph.Tests/Structures/Graphs/BidirectionalGraphTests.cs index f4016eb0f..79743fa67 100644 --- a/tests/QuikGraph.Tests/Structures/Graphs/BidirectionalGraphTests.cs +++ b/tests/QuikGraph.Tests/Structures/Graphs/BidirectionalGraphTests.cs @@ -746,6 +746,9 @@ public void RemoveVertexIf() { var graph = new BidirectionalGraph>(); RemoveVertexIf_Test(graph); + + graph = new BidirectionalGraph>(); + RemoveVertexIf_Test2(graph); } [Test] diff --git a/tests/QuikGraph.Tests/Structures/Graphs/ClusteredAdjacencyGraphTests.cs b/tests/QuikGraph.Tests/Structures/Graphs/ClusteredAdjacencyGraphTests.cs index 5e8796822..f9d8efbe3 100644 --- a/tests/QuikGraph.Tests/Structures/Graphs/ClusteredAdjacencyGraphTests.cs +++ b/tests/QuikGraph.Tests/Structures/Graphs/ClusteredAdjacencyGraphTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -526,10 +526,19 @@ public void RemoveVertexIf() var graph1 = new ClusteredAdjacencyGraph>(wrappedGraph1); RemoveVertexIf_Clusters_Test(graph1); + wrappedGraph1 = new AdjacencyGraph>(); + graph1 = new ClusteredAdjacencyGraph>(wrappedGraph1); + RemoveVertexIf_Clusters_Test2(graph1); + var wrappedGraph2 = new AdjacencyGraph>(); var graph2 = new ClusteredAdjacencyGraph>(wrappedGraph2); var subGraph2 = new ClusteredAdjacencyGraph>(graph2); RemoveVertexIf_Clusters_Test(subGraph2); + + wrappedGraph2 = new AdjacencyGraph>(); + graph2 = new ClusteredAdjacencyGraph>(wrappedGraph2); + subGraph2 = new ClusteredAdjacencyGraph>(graph2); + RemoveVertexIf_Clusters_Test2(subGraph2); } [Test] diff --git a/tests/QuikGraph.Tests/Structures/Graphs/GraphTestsBases/GraphTestsBase.RemoveVertices.cs b/tests/QuikGraph.Tests/Structures/Graphs/GraphTestsBases/GraphTestsBase.RemoveVertices.cs index eafa67459..5e461caf7 100644 --- a/tests/QuikGraph.Tests/Structures/Graphs/GraphTestsBases/GraphTestsBase.RemoveVertices.cs +++ b/tests/QuikGraph.Tests/Structures/Graphs/GraphTestsBases/GraphTestsBase.RemoveVertices.cs @@ -216,6 +216,53 @@ void CheckCounters(int expectedRemovedVertices, int expectedRemovedEdges) #endregion } + protected static void RemoveVertexIf_Test2( + [NotNull] IMutableVertexAndEdgeSet> graph) + { + int verticesRemoved = 0; + int edgesRemoved = 0; + + // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local + graph.VertexRemoved += v => + { + Assert.IsNotNull(v); + // ReSharper disable once AccessToModifiedClosure + ++verticesRemoved; + }; + // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local + graph.EdgeRemoved += e => + { + Assert.IsNotNull(e); + // ReSharper disable once AccessToModifiedClosure + ++edgesRemoved; + }; + + var edge11 = new Edge(1, 1); + var edge13 = new Edge(1, 3); + var edge24 = new Edge(2, 4); + var edge31 = new Edge(3, 1); + var edge32 = new Edge(3, 2); + var edge34 = new Edge(3, 4); + graph.AddVerticesAndEdgeRange(new[] { edge11, edge13, edge24, edge31, edge32, edge34 }); + + Assert.AreEqual(2, graph.RemoveVertexIf(vertex => vertex == 1 || vertex == 3)); + CheckCounters(2, 5); + AssertHasVertices(graph, new[] { 2, 4 }); + AssertHasEdges(graph, new[] { edge24 }); + + #region Local function + + void CheckCounters(int expectedRemovedVertices, int expectedRemovedEdges) + { + Assert.AreEqual(expectedRemovedVertices, verticesRemoved); + Assert.AreEqual(expectedRemovedEdges, edgesRemoved); + verticesRemoved = 0; + edgesRemoved = 0; + } + + #endregion + } + protected static void RemoveVertexIf_Clusters_Test( [NotNull] ClusteredAdjacencyGraph> graph) { @@ -237,6 +284,22 @@ protected static void RemoveVertexIf_Clusters_Test( AssertEmptyGraph(graph); } + protected static void RemoveVertexIf_Clusters_Test2( + [NotNull] ClusteredAdjacencyGraph> graph) + { + var edge11 = new Edge(1, 1); + var edge13 = new Edge(1, 3); + var edge24 = new Edge(2, 4); + var edge31 = new Edge(3, 1); + var edge32 = new Edge(3, 2); + var edge34 = new Edge(3, 4); + graph.AddVerticesAndEdgeRange(new[] { edge11, edge13, edge24, edge31, edge32, edge34 }); + + Assert.AreEqual(2, graph.RemoveVertexIf(vertex => vertex == 1 || vertex == 3)); + AssertHasVertices(graph, new[] { 2, 4 }); + AssertHasEdges(graph, new[] { edge24 }); + } + protected static void RemoveVertexIf_Throws_Test( [NotNull] IMutableVertexSet graph) where TVertex : class diff --git a/tests/QuikGraph.Tests/Structures/Graphs/UndirectedGraphTests.cs b/tests/QuikGraph.Tests/Structures/Graphs/UndirectedGraphTests.cs index 2fdef8af0..9b8fa0504 100644 --- a/tests/QuikGraph.Tests/Structures/Graphs/UndirectedGraphTests.cs +++ b/tests/QuikGraph.Tests/Structures/Graphs/UndirectedGraphTests.cs @@ -379,6 +379,9 @@ public void RemoveVertexIf() { var graph = new UndirectedGraph>(); RemoveVertexIf_Test(graph); + + graph = new UndirectedGraph>(); + RemoveVertexIf_Test2(graph); } [Test] @@ -659,6 +662,15 @@ private static void ClearEdgesCommon([NotNull, InstantHandle] Action(1, 1); + graph.AddVerticesAndEdgeRange(new[] { edge11, edge12, edge13, edge23, edge31, edge32 }); + + // Clear self edge + clearEdges(graph, 1); + + AssertHasEdges(graph, new[] { edge23, edge32 }); + CheckCounter(4); + #region Local function void CheckCounter(int expectedRemovedEdges) From ae67182f29de7b5e328b2aa974a9fb4350dfbf11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 10 Oct 2021 23:18:13 +0200 Subject: [PATCH 03/39] Clean various SonarQube issues. --- src/QuikGraph.Graphviz/Dot/GraphvizVertex.cs | 34 ++++++--- .../GraphMLDeserializer.cs | 12 +-- .../StronglyConnectedComponentAlgorithm.cs | 7 +- .../Algorithms/EulerianTrailAlgorithm.cs | 31 ++++---- .../TransitionFactoryImplicitGraph.cs | 15 ++-- .../GraphPartition/KernighanLinAlgorithm.cs | 4 +- .../ReverseEdgeAugmentorAlgorithm.cs | 16 ++-- .../EdgePredecessorRecorderObserver.cs | 9 +-- .../VertexPredecessorPathRecorderObserver.cs | 9 +-- src/QuikGraph/Algorithms/PageRankAlgorithm.cs | 10 +-- .../ShortestPath/YenShortestPathsAlgorithm.cs | 35 ++++----- .../SourceFirstTopologicalSortAlgorithm.cs | 10 +-- .../Algorithms/TransitiveAlgorithmHelper.cs | 3 +- .../Collections/ForestDisjointSet.cs | 4 +- .../Extensions/AlgorithmExtensions.cs | 4 +- .../Graphs/FilteredIncidenceGraph.cs | 11 +-- .../Structures/Graphs/AdjacencyGraph.cs | 54 +++----------- .../Structures/Graphs/ArrayAdjacencyGraph.cs | 9 +-- .../Graphs/ArrayBidirectionalGraph.cs | 9 +-- .../Structures/Graphs/ArrayUndirectedGraph.cs | 12 +-- .../Structures/Graphs/BidirectionalGraph.cs | 54 +++----------- .../Graphs/BidirectionalMatrixGraph.cs | 11 +-- .../Graphs/ClusteredAdjacencyGraph.cs | 33 +-------- .../Graphs/DelegateImplicitUndirectedGraph.cs | 11 +-- .../Graphs/DelegateIncidenceGraph.cs | 11 +-- .../Structures/Graphs/EdgeListGraph.cs | 22 +----- .../Graphs/UndirectedBidirectionalGraph.cs | 10 +-- .../Structures/Graphs/UndirectedGraph.cs | 73 +++---------------- 28 files changed, 164 insertions(+), 359 deletions(-) diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizVertex.cs b/src/QuikGraph.Graphviz/Dot/GraphvizVertex.cs index 22abd701a..f61179113 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizVertex.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizVertex.cs @@ -289,19 +289,10 @@ private void TextRelatedPropertiesToDot([NotNull] IDictionary pr #if SUPPORTS_AGGRESSIVE_INLINING [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void ShapeRelatedPropertiesToDot( - [CanBeNull] GraphvizVertex commonFormat, - [NotNull] IDictionary properties) + private void LabelOrRecordToDot( + [NotNull] IDictionary properties, + GraphvizVertexShape shape) { - if (Shape != GraphvizVertexShape.Unspecified) - { - properties["shape"] = Shape; - } - - GraphvizVertexShape shape = Shape == GraphvizVertexShape.Unspecified && commonFormat != null - ? commonFormat.Shape - : Shape; - if (shape == GraphvizVertexShape.Record) { // Priority to label to allow custom record generation process @@ -320,6 +311,25 @@ private void ShapeRelatedPropertiesToDot( ? (object)new HtmlString(Label) : Escape(Label); } + } + +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void ShapeRelatedPropertiesToDot( + [CanBeNull] GraphvizVertex commonFormat, + [NotNull] IDictionary properties) + { + if (Shape != GraphvizVertexShape.Unspecified) + { + properties["shape"] = Shape; + } + + GraphvizVertexShape shape = Shape == GraphvizVertexShape.Unspecified && commonFormat != null + ? commonFormat.Shape + : Shape; + + LabelOrRecordToDot(properties, shape); if (shape == GraphvizVertexShape.Polygon) { diff --git a/src/QuikGraph.Serialization/GraphMLDeserializer.cs b/src/QuikGraph.Serialization/GraphMLDeserializer.cs index ead44be06..8b9731e33 100644 --- a/src/QuikGraph.Serialization/GraphMLDeserializer.cs +++ b/src/QuikGraph.Serialization/GraphMLDeserializer.cs @@ -1,8 +1,9 @@ -#if SUPPORTS_GRAPHS_SERIALIZATION +#if SUPPORTS_GRAPHS_SERIALIZATION using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Xml; @@ -124,10 +125,11 @@ private static Delegate CreateSetDefaultDelegate( ILGenerator generator = method.GetILGenerator(); // We need to create the switch for each property - foreach (PropertySerializationInfo info in SerializationHelpers.GetAttributeProperties(elementType)) + IEnumerable properties = SerializationHelpers + .GetAttributeProperties(elementType) + .Select(info => info.Property); + foreach (PropertyInfo property in properties) { - PropertyInfo property = info.Property; - var defaultValueAttribute = Attribute.GetCustomAttribute(property, typeof(DefaultValueAttribute)) as DefaultValueAttribute; if (defaultValueAttribute is null) continue; @@ -270,7 +272,7 @@ public void Deserialize( worker.Deserialize(); } - private class ReaderWorker + private sealed class ReaderWorker { [NotNull] private readonly XmlReader _reader; diff --git a/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs b/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs index 5ba194120..fe1391248 100644 --- a/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -223,11 +223,12 @@ private void OnVertexDiscovered([NotNull] TVertex vertex) private void OnVertexFinished([NotNull] TVertex vertex) { - foreach (TEdge edge in VisitedGraph.OutEdges(vertex)) + foreach (TVertex target in VisitedGraph.OutEdges(vertex).Select(edge => edge.Target)) { - TVertex target = edge.Target; if (Components[target] == int.MaxValue) + { Roots[vertex] = MinDiscoverTime(Roots[vertex], Roots[target]); + } } if (EqualityComparer.Default.Equals(Roots[vertex], vertex)) diff --git a/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs b/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs index 242bdcd98..ebd4dbbaf 100644 --- a/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs +++ b/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -157,17 +157,18 @@ private bool Search([NotNull] TVertex vertex) /// Looks for a new path to add to the current vertex. /// /// True a new path was found, false otherwise. + [Pure] private bool Visit() { // Find a vertex that needs to be visited - foreach (TEdge edge in _circuit) + foreach (TVertex source in _circuit.Select(edge => edge.Source)) { - bool edgeFound = TrySelectSingleOutEdgeNotInCircuit(edge.Source, out TEdge foundEdge); + bool edgeFound = TrySelectSingleOutEdgeNotInCircuit(source, out TEdge foundEdge); if (!edgeFound) continue; OnVisitEdge(foundEdge); - _currentVertex = edge.Source; + _currentVertex = source; if (Search(_currentVertex)) return true; } @@ -181,6 +182,7 @@ private bool Visit() /// /// Graph to visit. /// Number of Eulerian trails. + [Pure] public static int ComputeEulerianPathCount( [NotNull] IVertexAndEdgeListGraph graph) { @@ -202,6 +204,7 @@ public static int ComputeEulerianPathCount( /// Merges the temporary circuit with the current circuit. /// /// True if all the graph edges are in the circuit. + [Pure] private bool CircuitAugmentation() { var newCircuit = new List(_circuit.Count + _temporaryCircuit.Count); @@ -274,21 +277,18 @@ protected override void InternalCompute() #endregion + [Pure] private bool HasEdgeToward([NotNull] TVertex u, [NotNull] TVertex v) { - bool foundEdge = false; - foreach (TEdge edge in VisitedGraph.OutEdges(v)) - { - if (EqualityComparer.Default.Equals(edge.Target, u)) - { - foundEdge = true; - break; - } - } + Debug.Assert(u != null); + Debug.Assert(v != null); - return foundEdge; + return VisitedGraph + .OutEdges(v) + .Any(outEdge => EqualityComparer.Default.Equals(outEdge.Target, u)); } + [Pure] private bool FindAdjacentOddVertex( [NotNull] TVertex u, [NotNull, ItemNotNull] ICollection oddVertices, @@ -297,9 +297,8 @@ private bool FindAdjacentOddVertex( { bool found = false; foundAdjacent = false; - foreach (TEdge edge in VisitedGraph.OutEdges(u)) + foreach (TVertex v in VisitedGraph.OutEdges(u).Select(outEdge => outEdge.Target)) { - TVertex v = edge.Target; if (!EqualityComparer.Default.Equals(v, u) && oddVertices.Contains(v)) { foundAdjacent = true; diff --git a/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs b/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs index 3543be6ff..7fae07a22 100644 --- a/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs +++ b/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_CLONEABLE +#if SUPPORTS_CLONEABLE using System; using System.Collections.Generic; using System.Diagnostics; @@ -242,16 +242,13 @@ private IEdgeList ExploreFactoriesForVertex([NotNull] TVertex ve if (edges is null) edges = new EdgeList(); - foreach (TEdge edge in transitionFactory.Apply(vertex)) + foreach (TEdge edge in transitionFactory.Apply(vertex).Where(edge => SuccessorVertexPredicate(edge.Target))) { - if (SuccessorVertexPredicate(edge.Target)) - { - AddToNotProcessedCacheIfNecessary(edge.Target, transitionFactory); + AddToNotProcessedCacheIfNecessary(edge.Target, transitionFactory); - if (SuccessorEdgePredicate(edge)) - { - edges.Add(edge); - } + if (SuccessorEdgePredicate(edge)) + { + edges.Add(edge); } } } diff --git a/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs b/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs index b8f8c8d91..408199dde 100644 --- a/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs +++ b/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -46,7 +46,7 @@ public KernighanLinAlgorithm( /// public Partition Partition { get; private set; } - private class SwapPair + private sealed class SwapPair { public TVertex Vertex1 { get; } public TVertex Vertex2 { get; } diff --git a/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs index 3429ebfc9..15feeeebf 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -79,23 +79,25 @@ private void OnReservedEdgeAdded([NotNull] TEdge edge) /// Edge to find its corresponding reversed one. /// Found reversed edge. /// True if the reversed edge was found, false otherwise. + [Pure] private bool FindReversedEdge([NotNull] TEdge edge, out TEdge foundReversedEdge) { Debug.Assert(edge != null); - foreach (TEdge reversedEdge in VisitedGraph.OutEdges(edge.Target)) + IEnumerable reversedEdges = VisitedGraph + .OutEdges(edge.Target) + .Where(reversedEdge => EqualityComparer.Default.Equals(reversedEdge.Target, edge.Source)); + foreach (TEdge reversedEdge in reversedEdges) { - if (EqualityComparer.Default.Equals(reversedEdge.Target, edge.Source)) - { - foundReversedEdge = reversedEdge; - return true; - } + foundReversedEdge = reversedEdge; + return true; } foundReversedEdge = default(TEdge); return false; } + [Pure] [NotNull, ItemNotNull] private IEnumerable FindEdgesToReverse() { diff --git a/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs index ccc256d24..ee88dd25e 100644 --- a/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -182,11 +182,8 @@ private void OnEdgeFinished([NotNull] TEdge finishedEdge) { Debug.Assert(finishedEdge != null); - foreach (TEdge edge in EdgesPredecessors.Values) - { - if (EqualityComparer.Default.Equals(finishedEdge, edge)) - return; - } + if (EdgesPredecessors.Values.Any(edge => EqualityComparer.Default.Equals(finishedEdge, edge))) + return; EndPathEdges.Add(finishedEdge); } diff --git a/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs index 0c2cf5908..5d8742bb6 100644 --- a/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -97,11 +97,8 @@ private void OnVertexFinished([NotNull] TVertex vertex) { Debug.Assert(vertex != null); - foreach (TEdge edge in VerticesPredecessors.Values) - { - if (EqualityComparer.Default.Equals(edge.Source, vertex)) - return; - } + if (VerticesPredecessors.Values.Any(edge => EqualityComparer.Default.Equals(edge.Source, vertex))) + return; EndPathVertices.Add(vertex); } diff --git a/src/QuikGraph/Algorithms/PageRankAlgorithm.cs b/src/QuikGraph/Algorithms/PageRankAlgorithm.cs index 9c968ea41..b269e6456 100644 --- a/src/QuikGraph/Algorithms/PageRankAlgorithm.cs +++ b/src/QuikGraph/Algorithms/PageRankAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -128,11 +128,9 @@ protected override void InternalCompute() double rank = pair.Value; // Compute sum of PR(pj)/L(pj) - double r = 0; - foreach (TEdge edge in filterGraph.InEdges(vertex)) - { - r += Ranks[edge.Source] / filterGraph.OutDegree(edge.Source); - } + double r = filterGraph.InEdges(vertex) + .Select(edge => edge.Source) + .Sum(source => Ranks[source] / filterGraph.OutDegree(source)); // Add sourceRank and store it double newRank = (1 - Damping) + Damping * r; diff --git a/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs index 092364a2a..4315ce555 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -150,17 +150,20 @@ public YenShortestPathsAlgorithm( _filter = filter ?? DefaultFilter; } + [Pure] [NotNull] private static IEnumerable DefaultFilter([NotNull] IEnumerable paths) { return paths; } + [Pure] private static double DefaultGetWeights([NotNull] EquatableTaggedEdge edge) { return edge.Tag; } + [Pure] private double GetPathDistance([ItemNotNull] SortedPath edges) { return edges.Sum(edge => _weights(edge)); @@ -211,6 +214,7 @@ private SortedPath GetInitialShortestPath() : (SortedPath?)null; } + [Pure] [CanBeNull] private static SortedPath? ExtractShortestPathCandidate( [NotNull] List shortestPaths, @@ -222,21 +226,18 @@ private SortedPath GetInitialShortestPath() { newPath = shortestPathCandidates.Dequeue(); isNewPath = true; - foreach (SortedPath path in shortestPaths) + // Check to see if this candidate path duplicates a previously found path + if (shortestPaths.Any(path => newPath.Value.Equals(path))) { - // Check to see if this candidate path duplicates a previously found path - if (newPath.Value.Equals(path)) - { - isNewPath = false; - newPath = null; - break; - } + isNewPath = false; + newPath = null; } } return newPath; } + [Pure] private bool SearchAndAddKthShortestPath( SortedPath previousPath, [NotNull] List shortestPaths, @@ -254,21 +255,17 @@ private bool SearchAndAddKthShortestPath( // The sequence of nodes from the source to the spur node of the previous k-shortest path EquatableTaggedEdge[] rootPath = previousPath.GetEdges(i); - foreach (SortedPath path in shortestPaths) + foreach (SortedPath path in shortestPaths.Where(path => rootPath.SequenceEqual(path.GetEdges(i)))) { - if (rootPath.SequenceEqual(path.GetEdges(i))) - { - // Remove the links that are part of the previous shortest paths which share the same root path - EquatableTaggedEdge edgeToRemove = path.GetEdge(i); - _edgesToRestore.Add(edgeToRemove); - _graph.RemoveEdge(edgeToRemove); - } + // Remove the links that are part of the previous shortest paths which share the same root path + EquatableTaggedEdge edgeToRemove = path.GetEdge(i); + _edgesToRestore.Add(edgeToRemove); + _graph.RemoveEdge(edgeToRemove); } var verticesToRestore = new List(); - foreach (EquatableTaggedEdge rootPathEdge in rootPath) + foreach (TVertex source in rootPath.Select(rootPathEdge => rootPathEdge.Source)) { - TVertex source = rootPathEdge.Source; if (!EqualityComparer.Default.Equals(spurVertex, source)) { verticesToRestore.Add(source); diff --git a/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs b/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs index 5c2d3a8b8..744c90162 100644 --- a/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using JetBrains.Annotations; @@ -108,13 +108,13 @@ protected override void InternalCompute() OnVertexAdded(vertex); // Update the count of its adjacent vertices - foreach (TEdge edge in VisitedGraph.OutEdges(vertex)) + foreach (TVertex target in VisitedGraph.OutEdges(vertex).Select(outEdge => outEdge.Target)) { - --InDegrees[edge.Target]; + --InDegrees[target]; - Debug.Assert(InDegrees[edge.Target] >= 0); + Debug.Assert(InDegrees[target] >= 0); - _heap.Update(edge.Target); + _heap.Update(target); } } diff --git a/src/QuikGraph/Algorithms/TransitiveAlgorithmHelper.cs b/src/QuikGraph/Algorithms/TransitiveAlgorithmHelper.cs index fb186d48b..764568485 100644 --- a/src/QuikGraph/Algorithms/TransitiveAlgorithmHelper.cs +++ b/src/QuikGraph/Algorithms/TransitiveAlgorithmHelper.cs @@ -59,9 +59,8 @@ public void InternalCompute( verticesAncestors[vertexId] = vertexAncestors; // Get indirect ancestors - foreach (TEdge inEdge in _graph.InEdges(vertexId)) + foreach (TVertex predecessor in _graph.InEdges(vertexId).Select(inEdge => inEdge.Source)) { - TVertex predecessor = inEdge.Source; vertexPredecessors.Add(predecessor); // Add all the ancestors of the predecessors diff --git a/src/QuikGraph/Collections/ForestDisjointSet.cs b/src/QuikGraph/Collections/ForestDisjointSet.cs index 38938f1f8..af9aa9000 100644 --- a/src/QuikGraph/Collections/ForestDisjointSet.cs +++ b/src/QuikGraph/Collections/ForestDisjointSet.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -17,7 +17,7 @@ public class ForestDisjointSet : IDisjointSet #if DEBUG [DebuggerDisplay("{" + nameof(_id) + "}:{" + nameof(Rank) + "}->{" + nameof(Parent) + "}")] #endif - private class Element + private sealed class Element { #if DEBUG private readonly int _id; diff --git a/src/QuikGraph/Extensions/AlgorithmExtensions.cs b/src/QuikGraph/Extensions/AlgorithmExtensions.cs index 765384c28..fb5e2478c 100644 --- a/src/QuikGraph/Extensions/AlgorithmExtensions.cs +++ b/src/QuikGraph/Extensions/AlgorithmExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -842,7 +842,7 @@ public static bool IsDirectedAcyclicGraph( return new DagTester().IsDag(graph); } - private class DagTester + private sealed class DagTester where TEdge : IEdge { private bool _isDag = true; diff --git a/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs index 1fb358347..e7f4c3225 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -50,13 +50,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) && VertexPredicate(target) && BaseGraph.TryGetEdges(source, target, out IEnumerable unfilteredEdges)) { - foreach (TEdge unfilteredEdge in unfilteredEdges) + foreach (TEdge unfilteredEdge in unfilteredEdges.Where(unfilteredEdge => EdgePredicate(unfilteredEdge))) { - if (EdgePredicate(unfilteredEdge)) - { - edge = unfilteredEdge; - return true; - } + edge = unfilteredEdge; + return true; } } diff --git a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs index f8add4644..704ea7031 100644 --- a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs @@ -170,13 +170,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (_vertexEdges.TryGetValue(source, out IEdgeList outEdges) && outEdges.Count > 0) { - foreach (TEdge outEdge in outEdges) + foreach (TEdge outEdge in outEdges.Where(outEdge => EqualityComparer.Default.Equals(outEdge.Target, target))) { - if (EqualityComparer.Default.Equals(outEdge.Target, target)) - { - edge = outEdge; - return true; - } + edge = outEdge; + return true; } } @@ -291,16 +288,7 @@ public virtual int AddVertexRange(IEnumerable vertices) if (verticesArray.Any(v => v == null)) throw new ArgumentNullException(nameof(vertices), "At least one vertex is null."); - int count = 0; - foreach (TVertex vertex in verticesArray) - { - if (AddVertex(vertex)) - { - ++count; - } - } - - return count; + return verticesArray.Count(AddVertex); } /// @@ -418,16 +406,7 @@ public int AddVerticesAndEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddVerticesAndEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddVerticesAndEdge); } #endregion @@ -473,16 +452,7 @@ public int AddEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddEdge); } /// @@ -507,25 +477,25 @@ private void RemoveInEdges([NotNull, InstantHandle] Predicate shouldRem Debug.Assert(shouldRemove != null); // Run over edges and remove each edge touching the vertices to remove - foreach (KeyValuePair> pair in _vertexEdges) + foreach (IEdgeList outEdges in _vertexEdges.Select(pair => pair.Value)) { // Collect indexes of edges to remove var indexesToRemove = new List(); var edgesToRemove = new List(); - for (int i = 0; i < pair.Value.Count; ++i) + for (int i = 0; i < outEdges.Count; ++i) { - TEdge edge = pair.Value[i]; - if (shouldRemove(edge.Target)) + TEdge outEdge = outEdges[i]; + if (shouldRemove(outEdge.Target)) { indexesToRemove.Add(i); - edgesToRemove.Add(edge); + edgesToRemove.Add(outEdge); } } // Remove collected edges for (int i = indexesToRemove.Count - 1; i >= 0; --i) { - pair.Value.RemoveAt(indexesToRemove[i]); + outEdges.RemoveAt(indexesToRemove[i]); } EdgeCount -= indexesToRemove.Count; diff --git a/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs index 69402f29b..2ddbc35fd 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs @@ -181,13 +181,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (_vertexOutEdges.TryGetValue(source, out TEdge[] outEdges)) { - foreach (TEdge outEdge in outEdges) + foreach (TEdge outEdge in outEdges.Where(outEdge => EqualityComparer.Default.Equals(outEdge.Target, target))) { - if (EqualityComparer.Default.Equals(outEdge.Target, target)) - { - edge = outEdge; - return true; - } + edge = outEdge; + return true; } } diff --git a/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs index bfa92057a..f1bba93c4 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs @@ -146,13 +146,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (_vertexEdges.TryGetValue(source, out InOutEdges inOutEdges)) { - foreach (TEdge outEdge in inOutEdges.OutEdges) + foreach (TEdge outEdge in inOutEdges.OutEdges.Where(outEdge => EqualityComparer.Default.Equals(outEdge.Target, target))) { - if (EqualityComparer.Default.Equals(outEdge.Target, target)) - { - edge = outEdge; - return true; - } + edge = outEdge; + return true; } } diff --git a/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs index b738fc137..560c04298 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -182,15 +182,9 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) target = temp; } - if (!_vertexEdges.TryGetValue(source, out TEdge[] adjacentEdges)) + if (_vertexEdges.TryGetValue(source, out TEdge[] adjacentEdges)) { - edge = default(TEdge); - return false; - } - - foreach (TEdge adjacentEdge in adjacentEdges) - { - if (EdgeEqualityComparer(adjacentEdge, source, target)) + foreach (TEdge adjacentEdge in adjacentEdges.Where(adjacentEdge => EdgeEqualityComparer(adjacentEdge, source, target))) { edge = adjacentEdge; return true; diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs index 06175c65d..026ff80ae 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs @@ -235,13 +235,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (_vertexOutEdges.TryGetValue(source, out IEdgeList outEdges) && outEdges.Count > 0) { - foreach (TEdge outEdge in outEdges) + foreach (TEdge outEdge in outEdges.Where(outEdge => EqualityComparer.Default.Equals(outEdge.Target, target))) { - if (EqualityComparer.Default.Equals(outEdge.Target, target)) - { - edge = outEdge; - return true; - } + edge = outEdge; + return true; } } @@ -386,16 +383,7 @@ public virtual int AddVertexRange(IEnumerable vertices) if (verticesArray.Any(v => v == null)) throw new ArgumentNullException(nameof(vertices), "At least one vertex is null."); - int count = 0; - foreach (TVertex vertex in verticesArray) - { - if (AddVertex(vertex)) - { - ++count; - } - } - - return count; + return verticesArray.Count(AddVertex); } /// @@ -542,16 +530,7 @@ public int AddEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddEdge); } /// @@ -673,16 +652,7 @@ public int AddVerticesAndEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddVerticesAndEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddVerticesAndEdge); } #endregion @@ -815,15 +785,15 @@ public void MergeVertex( RemoveVertex(vertex); // Add edges from each source to each target - foreach (TEdge source in inEdges) + foreach (TVertex source in inEdges.Select(source => source.Source)) { - foreach (TEdge target in outEdges) + IEnumerable targets = outEdges + .Where(target => !EqualityComparer.Default.Equals(vertex, target.Target)) + .Select(target => target.Target); + foreach (TVertex target in targets) { - if (EqualityComparer.Default.Equals(vertex, target.Target)) - continue; - // We add an new edge - AddEdgeInternal(edgeFactory(source.Source, target.Target)); + AddEdgeInternal(edgeFactory(source, target)); } } } diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs index 851e21a8a..073c5704b 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs @@ -529,16 +529,7 @@ public int AddEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddEdge); } /// diff --git a/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs index 10c0cc7c9..8ec3ae9db 100644 --- a/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs @@ -258,16 +258,7 @@ public virtual int AddVertexRange([NotNull, ItemNotNull] IEnumerable ve if (verticesArray.Any(v => v == null)) throw new ArgumentNullException(nameof(vertices), "At least one vertex is null."); - int count = 0; - foreach (TVertex vertex in verticesArray) - { - if (AddVertex(vertex)) - { - ++count; - } - } - - return count; + return verticesArray.Count(AddVertex); } /// @@ -367,16 +358,7 @@ public int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edg if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddVerticesAndEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddVerticesAndEdge); } /// @@ -409,16 +391,7 @@ public int AddEdgeRange([NotNull, ItemNotNull] IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddEdge); } private void RemoveChildEdge([NotNull] TEdge edge) diff --git a/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs index 50e381e46..d3a5a021a 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -115,13 +115,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (TryGetAdjacentEdges(source, out IEnumerable adjacentEdges)) { - foreach (TEdge adjacentEdge in adjacentEdges) + foreach (TEdge adjacentEdge in adjacentEdges.Where(adjacentEdge => EdgeEqualityComparer(adjacentEdge, source, target))) { - if (EdgeEqualityComparer(adjacentEdge, source, target)) - { - edge = adjacentEdge; - return true; - } + edge = adjacentEdge; + return true; } } diff --git a/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs index 1d6d6a721..ff9ef1c98 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -51,13 +51,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (TryGetOutEdges(source, out IEnumerable outEdges)) { - foreach (TEdge outEdge in outEdges) + foreach (TEdge outEdge in outEdges.Where(outEdge => EqualityComparer.Default.Equals(outEdge.Target, target))) { - if (EqualityComparer.Default.Equals(outEdge.Target, target)) - { - edge = outEdge; - return true; - } + edge = outEdge; + return true; } } diff --git a/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs b/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs index 262720fe6..0ff275fbd 100644 --- a/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs +++ b/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs @@ -153,16 +153,7 @@ public int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edg if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddVerticesAndEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddVerticesAndEdge); } /// @@ -194,16 +185,7 @@ public int AddEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddEdge); } /// diff --git a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs index 056bb932b..b29185f86 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs @@ -173,15 +173,9 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) _reorder(source, target, out source, out target); - if (!ContainsVertex(source)) + if (ContainsVertex(source)) { - edge = default(TEdge); - return false; - } - - foreach (TEdge adjacentEdge in AdjacentEdges(source)) - { - if (EdgeEqualityComparer(adjacentEdge, source, target)) + foreach (TEdge adjacentEdge in AdjacentEdges(source).Where(adjacentEdge => EdgeEqualityComparer(adjacentEdge, source, target))) { edge = adjacentEdge; return true; diff --git a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs index adb4edf04..a14485edb 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs @@ -181,16 +181,8 @@ public bool ContainsEdge(TEdge edge) if (edge == null) throw new ArgumentNullException(nameof(edge)); - if (!_adjacentEdges.TryGetValue(edge.Source, out IEdgeList adjacentEdges)) - return false; - - foreach (TEdge adjacentEdge in adjacentEdges) - { - if (EqualityComparer.Default.Equals(adjacentEdge, edge)) - return true; - } - - return false; + return _adjacentEdges.TryGetValue(edge.Source, out IEdgeList adjacentEdges) + && adjacentEdges.Any(adjacentEdge => EqualityComparer.Default.Equals(adjacentEdge, edge)); } /// @@ -207,13 +199,7 @@ private bool ContainsEdgeBetweenVertices([NotNull, ItemNotNull] IEnumerable EdgeEqualityComparer(e, source, target)); } #endregion @@ -271,13 +257,10 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) if (_adjacentEdges.TryGetValue(source, out IEdgeList adjacentEdges)) { - foreach (TEdge adjacentEdge in adjacentEdges) + foreach (TEdge adjacentEdge in adjacentEdges.Where(adjacentEdge => EdgeEqualityComparer(adjacentEdge, source, target))) { - if (EdgeEqualityComparer(adjacentEdge, source, target)) - { - edge = adjacentEdge; - return true; - } + edge = adjacentEdge; + return true; } } @@ -359,16 +342,7 @@ public int AddVertexRange(IEnumerable vertices) if (verticesArray.Any(v => v == null)) throw new ArgumentNullException(nameof(vertices), "At least one vertex is null."); - int count = 0; - foreach (TVertex vertex in verticesArray) - { - if (AddVertex(vertex)) - { - ++count; - } - } - - return count; + return verticesArray.Count(AddVertex); } [Pure] @@ -550,16 +524,7 @@ public int AddVerticesAndEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddVerticesAndEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddVerticesAndEdge); } /// @@ -598,16 +563,7 @@ public int AddEdgeRange(IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (AddEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(AddEdge); } /// @@ -728,16 +684,7 @@ public int RemoveEdges([NotNull, ItemNotNull] IEnumerable edges) if (edgesArray.Any(e => e == null)) throw new ArgumentNullException(nameof(edges), "At least one edge is null."); - int count = 0; - foreach (TEdge edge in edgesArray) - { - if (RemoveEdge(edge)) - { - ++count; - } - } - - return count; + return edgesArray.Count(RemoveEdge); } #endregion From 65dabe7c06ec8eed04b000e9b99ad1c1a686b058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 11 Oct 2021 20:01:57 +0200 Subject: [PATCH 04/39] Remove dependency to System.Reflection.TypeExtensions from QuikGraph. --- src/QuikGraph/Compatibility/TypeUtils.cs | 4 ++-- src/QuikGraph/Extensions/EdgeExtensions.cs | 6 +++++- src/QuikGraph/QuikGraph.csproj | 5 ----- .../Structures/Graphs/UndirectedBidirectionalGraph.cs | 4 ++++ src/QuikGraph/Structures/Graphs/UndirectedGraph.cs | 6 +++++- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/QuikGraph/Compatibility/TypeUtils.cs b/src/QuikGraph/Compatibility/TypeUtils.cs index 611693b3f..79d9540bf 100644 --- a/src/QuikGraph/Compatibility/TypeUtils.cs +++ b/src/QuikGraph/Compatibility/TypeUtils.cs @@ -1,4 +1,4 @@ -#if !SUPPORTS_TYPE_FULL_FEATURES +#if !SUPPORTS_TYPE_FULL_FEATURES using System; using System.Collections.Generic; using System.Reflection; @@ -32,7 +32,7 @@ internal static class TypeUtils }; /// - /// Get the of the given . + /// Gets the of the given . /// /// Kind of equivalent to the System function for compatibility, but not really... /// to get the . diff --git a/src/QuikGraph/Extensions/EdgeExtensions.cs b/src/QuikGraph/Extensions/EdgeExtensions.cs index 5d3197593..786a82373 100644 --- a/src/QuikGraph/Extensions/EdgeExtensions.cs +++ b/src/QuikGraph/Extensions/EdgeExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -295,7 +295,11 @@ public static bool TryGetPath( [NotNull] public static EdgeEqualityComparer GetUndirectedVertexEquality() { +#if SUPPORTS_TYPE_FULL_FEATURES if (typeof(IUndirectedEdge).IsAssignableFrom(typeof(TEdge))) +#else + if (typeof(IUndirectedEdge).GetTypeInfo().IsAssignableFrom(typeof(TEdge).GetTypeInfo())) +#endif return SortedVertexEquality; return UndirectedVertexEquality; } diff --git a/src/QuikGraph/QuikGraph.csproj b/src/QuikGraph/QuikGraph.csproj index ca88f992d..028bab8b9 100644 --- a/src/QuikGraph/QuikGraph.csproj +++ b/src/QuikGraph/QuikGraph.csproj @@ -76,9 +76,4 @@ Misc: QuikGraph .NET Standard 2.0 $(DefineConstants);NETSTANDARD2_0;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_SORTEDSET;SUPPORTS_AGGRESSIVE_INLINING;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) - - - - - \ No newline at end of file diff --git a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs index b29185f86..b6f02e74d 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs @@ -37,7 +37,11 @@ public UndirectedBidirectionalGraph([NotNull] IBidirectionalGraph).IsAssignableFrom(typeof(TEdge)) +#else + _reorder = typeof(IUndirectedEdge).GetTypeInfo().IsAssignableFrom(typeof(TEdge).GetTypeInfo()) +#endif ? (ReorderVertices)((TVertex source, TVertex target, out TVertex orderedSource, out TVertex orderedTarget) => { if (Comparer.Default.Compare(source, target) > 0) diff --git a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs index a14485edb..8e54fcb50 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -69,7 +69,11 @@ public UndirectedGraph(bool allowParallelEdges, [NotNull] EdgeEqualityComparer).IsAssignableFrom(typeof(TEdge)) +#else + _reorder = typeof(IUndirectedEdge).GetTypeInfo().IsAssignableFrom(typeof(TEdge).GetTypeInfo()) +#endif ? (ReorderVertices)((TVertex source, TVertex target, out TVertex orderedSource, out TVertex orderedTarget) => { if (Comparer.Default.Compare(source, target) > 0) From fa432af7d51a074ec7d6e5ebb3e59f05c01f874c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Tue, 12 Oct 2021 00:26:43 +0200 Subject: [PATCH 05/39] Update QuikGraph.Serialization dependencies. Also add target .NET Standard 2.1 to further reduce dependencies. --- .../QuikGraph.Serialization.csproj | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj index 356e3ffc8..58f6e2572 100644 --- a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj +++ b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj @@ -1,7 +1,7 @@ - net35;net40;netstandard1.3;netstandard2.0 + net35;net40;netstandard1.3;netstandard2.0;netstandard2.1 $(Generate_QuikGraph_Serialization) @@ -42,7 +42,7 @@ Updates: - + QuikGraph.Serialization .NET 3.5 @@ -61,7 +61,11 @@ Updates: QuikGraph.Serialization .NET Standard 2.0 $(DefineConstants);NETSTANDARD2_0;SUPPORTS_SERIALIZATION;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) - + + QuikGraph.Serialization .NET Standard 2.1 + $(DefineConstants);NETSTANDARD2_1;SUPPORTS_SERIALIZATION;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) + + @@ -69,9 +73,9 @@ Updates: - + - + From 4db1ceafc72a1b970cbb9e77c1052979629468af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Wed, 13 Oct 2021 22:00:54 +0200 Subject: [PATCH 06/39] Complete xml documentation related to exceptions and fix some doc generation issues. --- src/QuikGraph.Data/DataRelationEdge.cs | 5 +- src/QuikGraph.Data/DataSetGraph.cs | 3 +- src/QuikGraph.Data/DataSetGraphExtensions.cs | 8 +- .../DataSetGraphPopulatorAlgorithm.cs | 10 +- .../DataSetGraphvizAlgorithm.cs | 10 +- src/QuikGraph.Graphviz/Dot/GraphvizEdge.cs | 5 + .../Dot/GraphvizEdgeExtremity.cs | 1 + .../Dot/GraphvizEdgeLabel.cs | 1 + src/QuikGraph.Graphviz/Dot/GraphvizFont.cs | 2 + src/QuikGraph.Graphviz/Dot/GraphvizGraph.cs | 1 + src/QuikGraph.Graphviz/Dot/GraphvizLayer.cs | 4 +- .../Dot/GraphvizLayerCollection.cs | 18 ++- src/QuikGraph.Graphviz/Dot/GraphvizRecord.cs | 3 +- .../Dot/GraphvizRecordCell.cs | 3 +- .../Dot/GraphvizRecordCellCollection.cs | 15 ++- src/QuikGraph.Graphviz/Dot/GraphvizSize.cs | 4 +- .../Events/FormatClusterEventArgs.cs | 2 + .../Extensions/GraphvizExtensions.cs | 9 +- src/QuikGraph.Graphviz/FileDotEngine.cs | 4 +- src/QuikGraph.Graphviz/GraphvizAlgorithm.cs | 17 +++ src/QuikGraph.Graphviz/Helpers/DotEscapers.cs | 5 +- src/QuikGraph.Graphviz/Helpers/HtmlString.cs | 1 + .../Interfaces/IDotEngine.cs | 4 +- .../Renderers/CondensatedGraphRenderer.cs | 1 + .../EdgeMergeCondensatedGraphRenderer.cs | 1 + .../Renderers/GraphRendererBase.cs | 1 + .../Events/MsaglEdgeEventArgs.cs | 8 +- .../Events/MsaglVertexEventArgs.cs | 8 +- .../MsaglDefaultGraphPopulator.cs | 5 +- src/QuikGraph.MSAGL/MsaglGraphExtensions.cs | 35 ++++- src/QuikGraph.MSAGL/MsaglGraphPopulator.cs | 13 +- .../MsaglIdentifiableGraphPopulator.cs | 4 +- .../MsaglToStringGraphPopulator.cs | 3 +- src/QuikGraph.Petri/Interfaces/IExpression.cs | 3 +- .../Interfaces/IMutablePetriNet.cs | 14 +- .../Interfaces/IPetriVertex.cs | 4 +- src/QuikGraph.Petri/PetriNetSimulator.cs | 3 +- src/QuikGraph.Petri/Structures/Arc.cs | 7 +- src/QuikGraph.Petri/Structures/PetriNet.cs | 3 +- src/QuikGraph.Petri/Structures/Place.cs | 3 +- src/QuikGraph.Petri/Structures/Transition.cs | 4 +- .../DirectedGraphMLAlgorithm.cs | 11 +- .../DirectedGraphMLExtensions.cs | 78 +++++++---- .../GraphMLDeserializer.cs | 19 ++- .../GraphMLExtensions.cs | 61 ++++++++- .../GraphMLSerializer.cs | 14 +- .../GraphMLXmlResolver.cs | 3 +- .../Helpers/SerializationHelpers.cs | 6 +- .../SerializationExtensions.cs | 61 +++++++-- .../XmlReaderExtensions.cs | 25 +++- .../XmlSerializableGraph.cs | 5 +- .../XmlWriterExtensions.cs | 2 +- src/QuikGraph/Algorithms/AlgorithmBase.cs | 27 +++- .../Assignment/HungarianAlgorithm.cs | 38 ++++-- .../Assignment/HungarianIteration.cs | 6 + .../Cliques/MaximumCliqueAlgorithmBase.cs | 4 +- .../CondensationGraphAlgorithm.cs | 3 +- .../Algorithms/Condensation/CondensedEdge.cs | 4 +- .../EdgeMergeCondensationGraphAlgorithm.cs | 7 +- .../Algorithms/Condensation/MergedEdge.cs | 8 +- .../ConnectedComponentsAlgorithm.cs | 7 +- ...IncrementalConnectedComponentsAlgorithm.cs | 15 ++- .../StronglyConnectedComponentAlgorithm.cs | 5 + .../WeaklyConnectedComponentsAlgorithm.cs | 19 ++- .../Algorithms/EulerianTrailAlgorithm.cs | 25 +++- .../CloneableVertexGraphExplorerAlgorithm.cs | 18 ++- .../Exploration/ITransitionFactory.cs | 4 +- .../TransitionFactoryImplicitGraph.cs | 22 ++- .../GraphPartition/KernighanLinAlgorithm.cs | 11 ++ .../Algorithms/GraphPartition/Partition.cs | 6 +- .../Algorithms/IsEulerianGraphAlgorithm.cs | 4 +- .../Algorithms/IsHamiltonianGraphAlgorithm.cs | 4 +- .../MaximumBipartiteMatchingAlgorithm.cs | 7 +- .../AllVerticesGraphAugmentorAlgorithm.cs | 8 +- ...iteToMaximumFlowGraphAugmentorAlgorithm.cs | 10 ++ .../EdmondsKarpMaximumFlowAlgorithm.cs | 18 ++- .../GraphAugmentorAlgorithmBase.cs | 5 +- .../MaximumFlow/GraphBalancingAlgorithm.cs | 30 +++-- .../MaximumFlow/MaximumFlowAlgorithmBase.cs | 13 +- .../MultiSourceSinkGraphAugmentorAlgorithm.cs | 12 +- .../ReverseEdgeAugmentorAlgorithm.cs | 12 +- .../KruskalMinimumSpanningTreeAlgorithm.cs | 10 +- .../PrimMinimumSpanningTreeAlgorithm.cs | 6 +- .../EdgePredecessorRecorderObserver.cs | 6 + .../Observers/EdgeRecorderObserver.cs | 3 +- ...ndirectedVertexDistanceRecorderObserver.cs | 6 +- ...rectedVertexPredecessorRecorderObserver.cs | 7 +- .../VertexDistanceRecorderObserver.cs | 8 +- .../VertexPredecessorPathRecorderObserver.cs | 8 +- .../VertexPredecessorRecorderObserver.cs | 7 +- .../Observers/VertexRecorderObserver.cs | 3 +- .../Observers/VertexTimeStamperObserver.cs | 9 +- src/QuikGraph/Algorithms/PageRankAlgorithm.cs | 4 + .../Algorithms/RandomGraphFactory.cs | 32 ++++- .../CyclePoppingRandomTreeAlgorithm.cs | 16 ++- .../Algorithms/RandomWalks/IEdgeChain.cs | 8 +- .../RandomWalks/RandomWalkAlgorithm.cs | 9 +- .../VanishingWeightedMarkovEdgeChain.cs | 4 +- .../RandomWalks/WeightedMarkedEdgeChain.cs | 3 +- .../WeightedMarkovEdgeChainBase.cs | 3 +- ...offmanPavleyRankedShortestPathAlgorithm.cs | 21 ++- .../RankedShortestPathAlgorithmBase.cs | 5 +- .../Algorithms/RootedAlgorithmBase.cs | 16 ++- .../Algorithms/RootedSearchAlgorithmBase.cs | 16 ++- .../BestFirstFrontierSearchAlgorithm.cs | 10 +- .../BidirectionalDepthFirstSearchAlgorithm.cs | 12 +- .../Search/BreadthFirstSearchAlgorithm.cs | 19 ++- .../Search/DepthFirstSearchAlgorithm.cs | 18 ++- .../Search/EdgeDepthFirstSearchAlgorithm.cs | 12 +- .../ImplicitDepthFirstSearchAlgorithm.cs | 7 +- .../ImplicitEdgeDepthFirstSearchAlgorithm.cs | 11 +- .../UndirectedBreathFirstSearchAlgorithm.cs | 13 +- .../UndirectedDepthFirstSearchAlgorithm.cs | 15 ++- .../Algorithms/Services/AlgorithmServices.cs | 4 +- .../Algorithms/Services/CancelManager.cs | 4 + .../AStarShortestPathAlgorithm.cs | 13 ++ .../BellmanFordShortestPathAlgorithm.cs | 13 +- .../ShortestPath/DagShortestPathAlgorithm.cs | 12 ++ .../DijkstraShortestPathAlgorithm.cs | 10 ++ .../FloydWarshallAllShortestPathAlgorithm.cs | 23 +++- .../ShortestPath/ShortestPathAlgorithmBase.cs | 7 + ...UndirectedDijkstraShortestPathAlgorithm.cs | 10 ++ .../UndirectedShortestPathAlgorithmBase.cs | 14 +- .../ShortestPath/YenShortestPathsAlgorithm.cs | 28 ++-- src/QuikGraph/Algorithms/TSP/TSP.cs | 4 +- src/QuikGraph/Algorithms/TSP/TasksManager.cs | 1 + ...rjanOfflineLeastCommonAncestorAlgorithm.cs | 11 +- ...stBidirectionalTopologicalSortAlgorithm.cs | 6 +- .../SourceFirstTopologicalSortAlgorithm.cs | 3 +- .../TopologicalSortAlgorithm.cs | 3 +- ...UndirectedFirstTopologicalSortAlgorithm.cs | 5 +- .../UndirectedTopologicalSortAlgorithm.cs | 3 +- .../Algorithms/TransitiveClosureAlgorithm.cs | 6 +- .../TransitiveReductionAlgorithm.cs | 10 +- .../VertexColoringAlgorithm.cs | 1 + ...inimumVertexCoverApproximationAlgorithm.cs | 6 +- src/QuikGraph/Collections/BinaryHeap.cs | 37 +++-- src/QuikGraph/Collections/BinaryQueue.cs | 5 +- .../Collections/EdgeEdgeDictionary.cs | 10 +- src/QuikGraph/Collections/EdgeList.cs | 4 +- src/QuikGraph/Collections/FibonacciHeap.cs | 21 ++- .../Collections/FibonacciHeapCell.cs | 6 +- src/QuikGraph/Collections/FibonacciQueue.cs | 11 +- .../Collections/ForestDisjointSet.cs | 3 + src/QuikGraph/Collections/Queue.cs | 4 +- src/QuikGraph/Collections/SoftHeap.cs | 17 ++- .../Collections/VertexEdgeDictionary.cs | 8 +- src/QuikGraph/Collections/VertexList.cs | 4 +- src/QuikGraph/Compatibility/SortedSet.cs | 28 ++-- src/QuikGraph/Events/EdgeEventArgs.cs | 3 +- .../Events/UndirectedEdgeEventArgs.cs | 3 +- src/QuikGraph/Events/VertexEventArgs.cs | 3 +- .../Exceptions/NegativeCapacityException.cs | 7 +- .../Exceptions/NegativeCycleGraphException.cs | 7 +- .../Exceptions/NegativeWeightException.cs | 7 +- .../Exceptions/NoPathFoundException.cs | 7 +- .../Exceptions/NonAcyclicGraphException.cs | 7 +- .../NonStronglyConnectedGraphException.cs | 7 +- .../ParallelEdgeNotAllowedException.cs | 7 +- .../Exceptions/QuikGraphException.cs | 7 +- .../Exceptions/VertexNotFoundException.cs | 7 +- .../Extensions/AlgorithmExtensions.cs | 126 +++++++++++++++++- src/QuikGraph/Extensions/EdgeExtensions.cs | 25 +++- src/QuikGraph/Extensions/GraphExtensions.cs | 70 +++++++++- src/QuikGraph/Helpers/CryptoRandom.cs | 6 +- src/QuikGraph/Helpers/GraphEqualityHelpers.cs | 4 +- .../Algorithms/IDistancesCollection.cs | 6 +- .../Algorithms/IVertexColorizerAlgorithm.cs | 4 +- .../Algorithms/Observers/IObserver.cs | 7 +- .../Interfaces/Collections/IDisjointSet.cs | 9 +- .../Interfaces/Collections/IQueue.cs | 4 +- .../Interfaces/Edges/ICloneableEdge.cs | 4 +- src/QuikGraph/Interfaces/Edges/IEdgeSet.cs | 3 +- .../Graphs/IBidirectionalIncidenceGraph.cs | 14 +- .../Interfaces/Graphs/IClusteredGraph.cs | 3 +- src/QuikGraph/Interfaces/Graphs/IHierarchy.cs | 23 +++- .../Interfaces/Graphs/IImplicitGraph.cs | 12 +- .../Graphs/IImplicitUndirectedGraph.cs | 15 ++- .../Interfaces/Graphs/IIncidenceGraph.cs | 8 +- .../Graphs/IMutableBidirectionalGraph.cs | 6 +- .../Graphs/IMutableEdgeListGraph.cs | 8 +- .../Graphs/IMutableIncidenceGraph.cs | 5 +- .../Graphs/IMutableUndirectedGraph.cs | 5 +- .../Graphs/IMutableVertexAndEdgeSet.cs | 6 +- .../Graphs/ITermBidirectionalGraph.cs | 28 +++- .../Interfaces/Vertices/IImplicitVertexSet.cs | 3 +- .../Interfaces/Vertices/IMutableVertexSet.cs | 8 +- .../Graphs/FilteredBidirectionalGraph.cs | 5 +- .../Graphs/FilteredEdgeListGraph.cs | 5 +- .../Predicates/Graphs/FilteredGraph.cs | 6 +- .../Graphs/FilteredImplicitGraph.cs | 5 +- .../Graphs/FilteredImplicitVertexSetGraph.cs | 5 +- .../Graphs/FilteredIncidenceGraph.cs | 3 + .../Graphs/FilteredUndirectedGraph.cs | 5 +- .../Graphs/FilteredVertexAndEdgeListGraph.cs | 5 +- .../Graphs/FilteredVertexListGraph.cs | 5 +- .../Predicates/InDictionaryVertexPredicate.cs | 4 +- .../Predicates/IsolatedVertexPredicate.cs | 4 +- .../Predicates/ResidualEdgePrediate.cs | 5 +- .../ReversedResidualEdgePredicate.cs | 5 +- .../Predicates/SinkVertexPredicate.cs | 4 +- src/QuikGraph/Structures/Edges/Edge.cs | 4 +- .../Structures/Edges/EquatableEdge.cs | 4 +- .../Structures/Edges/EquatableTaggedEdge.cs | 4 +- .../Structures/Edges/EquatableTermEdge.cs | 8 +- .../Edges/EquatableUndirectedEdge.cs | 4 +- src/QuikGraph/Structures/Edges/SEdge.cs | 4 +- .../Structures/Edges/SEquatableEdge.cs | 9 +- .../Structures/Edges/SEquatableTaggedEdge.cs | 9 +- .../Structures/Edges/SReversedEdge.cs | 3 +- src/QuikGraph/Structures/Edges/STaggedEdge.cs | 4 +- .../Structures/Edges/STaggedUndirectedEdge.cs | 7 +- .../Structures/Edges/SUndirectedEdge.cs | 4 +- src/QuikGraph/Structures/Edges/TaggedEdge.cs | 4 +- .../Structures/Edges/TaggedUndirectedEdge.cs | 4 +- src/QuikGraph/Structures/Edges/TermEdge.cs | 8 +- .../Structures/Edges/UndirectedEdge.cs | 7 +- .../Structures/Graphs/AdjacencyGraph.cs | 7 +- .../Structures/Graphs/ArrayAdjacencyGraph.cs | 19 +-- .../Graphs/ArrayBidirectionalGraph.cs | 21 +-- .../Structures/Graphs/ArrayUndirectedGraph.cs | 30 ++--- .../Graphs/BidirectionalAdapterGraph.cs | 1 + .../Structures/Graphs/BidirectionalGraph.cs | 5 + .../Graphs/BidirectionalMatrixGraph.cs | 6 +- .../Graphs/ClusteredAdjacencyGraph.cs | 21 +++ .../Graphs/CompressedSparseRowGraph.cs | 21 +-- .../DelegateBidirectionalIncidenceGraph.cs | 2 + .../Graphs/DelegateImplicitGraph.cs | 3 +- .../Graphs/DelegateImplicitUndirectedGraph.cs | 3 + .../Graphs/DelegateIncidenceGraph.cs | 1 + .../Graphs/DelegateUndirectedGraph.cs | 4 +- .../Graphs/DelegateVertexAndEdgeListGraph.cs | 2 + .../Structures/Graphs/EdgeListGraph.cs | 4 + .../Graphs/ReversedBidirectionalGraph.cs | 3 +- .../Graphs/UndirectedBidirectionalGraph.cs | 8 +- .../Structures/Graphs/UndirectedGraph.cs | 8 +- .../DirectedGraphMLExtensionsTests.cs | 6 +- .../GraphMLSerializerTests.cs | 2 +- .../Algorithms/RandomGraphFactoryTests.cs | 46 ++++--- .../YenShortestPathsAlgorithmTests.cs | 39 +++--- 240 files changed, 1913 insertions(+), 560 deletions(-) diff --git a/src/QuikGraph.Data/DataRelationEdge.cs b/src/QuikGraph.Data/DataRelationEdge.cs index 1cb574453..2afc2a041 100644 --- a/src/QuikGraph.Data/DataRelationEdge.cs +++ b/src/QuikGraph.Data/DataRelationEdge.cs @@ -1,11 +1,11 @@ -using System; +using System; using System.Data; using JetBrains.Annotations; namespace QuikGraph.Data { /// - /// Represents a relation between s. + /// Represents a relation between s. /// public sealed class DataRelationEdge : IEdge { @@ -13,6 +13,7 @@ public sealed class DataRelationEdge : IEdge /// Initializes a new instance of the class. /// /// Data relation. + /// is . public DataRelationEdge([NotNull] DataRelation relation) { Relation = relation ?? throw new ArgumentNullException(nameof(relation)); diff --git a/src/QuikGraph.Data/DataSetGraph.cs b/src/QuikGraph.Data/DataSetGraph.cs index 918ab1e77..f4e605fc2 100644 --- a/src/QuikGraph.Data/DataSetGraph.cs +++ b/src/QuikGraph.Data/DataSetGraph.cs @@ -10,7 +10,7 @@ namespace QuikGraph.Data public class DataSetGraph : BidirectionalGraph { /// - /// Wrapped . + /// Wrapped . /// public DataSet DataSet { get; } @@ -18,6 +18,7 @@ public class DataSetGraph : BidirectionalGraph /// Initializes a new instance of the class. /// /// Set of data. + /// is . internal DataSetGraph([NotNull] DataSet dataSet) { DataSet = dataSet ?? throw new ArgumentNullException(nameof(dataSet)); diff --git a/src/QuikGraph.Data/DataSetGraphExtensions.cs b/src/QuikGraph.Data/DataSetGraphExtensions.cs index 8f0ec5486..28f38580f 100644 --- a/src/QuikGraph.Data/DataSetGraphExtensions.cs +++ b/src/QuikGraph.Data/DataSetGraphExtensions.cs @@ -4,15 +4,16 @@ namespace QuikGraph.Data { /// - /// Extensions related to and . + /// Extensions related to and . /// public static class DataSetGraphExtensions { /// /// Converts this into a graph representation of it. /// - /// to convert to graph. - /// Graph representing the . + /// to convert to graph. + /// Graph representing the . + /// is . [Pure] [NotNull] public static DataSetGraph ToGraph([NotNull] this DataSet dataSet) @@ -29,6 +30,7 @@ public static DataSetGraph ToGraph([NotNull] this DataSet dataSet) /// /// Graph to convert. /// Graph serialized in DOT format. + /// is . [Pure] [NotNull] public static string ToGraphviz([NotNull] this DataSetGraph graph) diff --git a/src/QuikGraph.Data/DataSetGraphPopulatorAlgorithm.cs b/src/QuikGraph.Data/DataSetGraphPopulatorAlgorithm.cs index 75ab9822f..005aad8a0 100644 --- a/src/QuikGraph.Data/DataSetGraphPopulatorAlgorithm.cs +++ b/src/QuikGraph.Data/DataSetGraphPopulatorAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data; using JetBrains.Annotations; using QuikGraph.Algorithms; @@ -6,12 +6,12 @@ namespace QuikGraph.Data { /// - /// Algorithm that take a and convert it as a graph representation. + /// Algorithm that take a and convert it as a graph representation. /// public sealed class DataSetGraphPopulatorAlgorithm : AlgorithmBase> { /// - /// to represent as a graph. + /// to represent as a graph. /// [NotNull] public DataSet DataSet { get; } @@ -20,7 +20,9 @@ public sealed class DataSetGraphPopulatorAlgorithm : AlgorithmBase class. /// /// Graph to fill from . - /// to use to fill . + /// to use to fill . + /// is . + /// is . public DataSetGraphPopulatorAlgorithm( [NotNull] IMutableVertexAndEdgeSet visitedGraph, [NotNull] DataSet dataSet) diff --git a/src/QuikGraph.Data/DataSetGraphvizAlgorithm.cs b/src/QuikGraph.Data/DataSetGraphvizAlgorithm.cs index 996e67760..41affebab 100644 --- a/src/QuikGraph.Data/DataSetGraphvizAlgorithm.cs +++ b/src/QuikGraph.Data/DataSetGraphvizAlgorithm.cs @@ -16,6 +16,7 @@ public class DataSetGraphvizAlgorithm : GraphvizAlgorithm class. /// /// Graph to convert to DOT. + /// is . public DataSetGraphvizAlgorithm([NotNull] DataSetGraph visitedGraph) : base(visitedGraph) { @@ -27,6 +28,7 @@ public DataSetGraphvizAlgorithm([NotNull] DataSetGraph visitedGraph) /// /// Graph to convert to DOT. /// Target output image type. + /// is . public DataSetGraphvizAlgorithm( [NotNull] DataSetGraph visitedGraph, GraphvizImageType imageType) @@ -45,10 +47,10 @@ private void InitializeFormat() } /// - /// Formats a (a table). + /// Formats a (a table). /// - /// - /// + /// The performing the formatting. + /// Vertex event arguments. protected virtual void FormatTable([NotNull] object sender, [NotNull] FormatVertexEventArgs args) { Debug.Assert(sender != null); @@ -95,6 +97,8 @@ protected virtual void FormatTable([NotNull] object sender, [NotNull] FormatVert /// /// Formats a (a relation between tables). /// + /// The performing the formatting. + /// Edge event arguments. protected virtual void FormatRelation([NotNull] object sender, [NotNull] FormatEdgeEventArgs args) { Debug.Assert(sender != null); diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizEdge.cs b/src/QuikGraph.Graphviz/Dot/GraphvizEdge.cs index 2f0e1560b..3e1e8ceed 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizEdge.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizEdge.cs @@ -28,6 +28,7 @@ public class GraphvizEdge /// /// Label. /// + /// Set value is . [NotNull] public GraphvizEdgeLabel Label { @@ -78,6 +79,8 @@ public GraphvizEdgeLabel Label /// /// Edge head. /// + /// Set value is . + /// Set extremity is not corresponding to a head one. [NotNull] public GraphvizEdgeExtremity Head { @@ -110,6 +113,8 @@ public GraphvizEdgeExtremity Head /// /// Tail. /// + /// Set value is . + /// Set extremity is not corresponding to a tail one. [NotNull] public GraphvizEdgeExtremity Tail { diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs b/src/QuikGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs index e41c05cc1..6a6358646 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizEdgeExtremity.cs @@ -81,6 +81,7 @@ public GraphvizEdgeExtremity(bool isHead) /// Adds this edge extremity parameters to the given map. /// /// Parameter map to fill. + /// is . public void AddParameters([NotNull] IDictionary parameters) { if (parameters is null) diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizEdgeLabel.cs b/src/QuikGraph.Graphviz/Dot/GraphvizEdgeLabel.cs index ce566be09..2c95e1b15 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizEdgeLabel.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizEdgeLabel.cs @@ -62,6 +62,7 @@ public class GraphvizEdgeLabel /// Adds this edge label parameters to the given map. /// /// Parameter map to fill. + /// is . public void AddParameters([NotNull] IDictionary parameters) { if (parameters is null) diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizFont.cs b/src/QuikGraph.Graphviz/Dot/GraphvizFont.cs index 787f3dd71..c58499792 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizFont.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizFont.cs @@ -28,6 +28,8 @@ public sealed class GraphvizFont /// /// Font name. /// Font size. + /// is . + /// is negative or equal to 0. public GraphvizFont([NotNull] string name, float sizeInPoints) { if (string.IsNullOrEmpty(name)) diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizGraph.cs b/src/QuikGraph.Graphviz/Dot/GraphvizGraph.cs index 1e10c2811..800826dac 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizGraph.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizGraph.cs @@ -24,6 +24,7 @@ public class GraphvizGraph /// /// Graph name. /// + /// Set value is . public string Name { get => _name; diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizLayer.cs b/src/QuikGraph.Graphviz/Dot/GraphvizLayer.cs index e71fbd72b..46bdc354d 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizLayer.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizLayer.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Graphviz.Dot @@ -15,6 +15,7 @@ public class GraphvizLayer /// Initializes a new instance of the class. /// /// Layer name. + /// is or empty. public GraphvizLayer([NotNull] string name) { SetName(name); @@ -32,6 +33,7 @@ private void SetName([NotNull] string name) /// /// Layer name. /// + /// Set value is or empty. public string Name { get => _name; diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizLayerCollection.cs b/src/QuikGraph.Graphviz/Dot/GraphvizLayerCollection.cs index 81038fd39..f19bfe13e 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizLayerCollection.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizLayerCollection.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using JetBrains.Annotations; @@ -23,18 +24,20 @@ public GraphvizLayerCollection() /// /// Initializes a new instance of the class. /// - /// The list that is wrapped by the new collection. - public GraphvizLayerCollection([NotNull, ItemNotNull] GraphvizLayer[] list) - : base(list) + /// The collection that is wrapped by the new collection. + /// is . + public GraphvizLayerCollection([NotNull, ItemNotNull] IList collection) + : base(collection) { } /// /// Initializes a new instance of the class. /// - /// The list that is wrapped by the new collection. - public GraphvizLayerCollection([NotNull, ItemNotNull] GraphvizLayerCollection list) - : base(list) + /// The collection that is wrapped by the new collection. + /// is . + public GraphvizLayerCollection([NotNull, ItemNotNull] GraphvizLayerCollection collection) + : base(collection) { } @@ -45,6 +48,7 @@ public GraphvizLayerCollection([NotNull, ItemNotNull] GraphvizLayerCollection li /// Allowed collection item separators. /// See more /// + /// Set value is or empty. [NotNull] public string Separators { diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizRecord.cs b/src/QuikGraph.Graphviz/Dot/GraphvizRecord.cs index 811655f02..63aa28246 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizRecord.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizRecord.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Text; using JetBrains.Annotations; @@ -18,6 +18,7 @@ public class GraphvizRecord /// /// Record cells. /// + /// Set value is . [NotNull, ItemNotNull] public GraphvizRecordCellCollection Cells { diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizRecordCell.cs b/src/QuikGraph.Graphviz/Dot/GraphvizRecordCell.cs index 1d7e32f7f..f2bd95845 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizRecordCell.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizRecordCell.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Text; using JetBrains.Annotations; using static QuikGraph.Graphviz.DotEscapers; @@ -19,6 +19,7 @@ public class GraphvizRecordCell /// /// Record cells. /// + /// Set value is . [NotNull, ItemNotNull] public GraphvizRecordCellCollection Cells { diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs b/src/QuikGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs index b1c2275c3..690acb650 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizRecordCellCollection.cs @@ -1,6 +1,7 @@ -#if SUPPORTS_SERIALIZATION +#if SUPPORTS_SERIALIZATION using System; #endif +using System.Collections.Generic; using System.Collections.ObjectModel; using JetBrains.Annotations; @@ -24,18 +25,18 @@ public GraphvizRecordCellCollection() /// /// Initializes a new instance of the class. /// - /// The list that is wrapped by the new collection. - public GraphvizRecordCellCollection([NotNull, ItemNotNull] GraphvizRecordCell[] list) - : base(list) + /// The collection that is wrapped by the new collection. + public GraphvizRecordCellCollection([NotNull, ItemNotNull] IList collection) + : base(collection) { } /// /// Initializes a new instance of the class. /// - /// The list that is wrapped by the new collection. - public GraphvizRecordCellCollection([NotNull, ItemNotNull] GraphvizRecordCellCollection list) - : base(list) + /// The collection that is wrapped by the new collection. + public GraphvizRecordCellCollection([NotNull, ItemNotNull] GraphvizRecordCellCollection collection) + : base(collection) { } } diff --git a/src/QuikGraph.Graphviz/Dot/GraphvizSize.cs b/src/QuikGraph.Graphviz/Dot/GraphvizSize.cs index 21450476c..06fc974d2 100644 --- a/src/QuikGraph.Graphviz/Dot/GraphvizSize.cs +++ b/src/QuikGraph.Graphviz/Dot/GraphvizSize.cs @@ -43,6 +43,7 @@ public struct GraphvizSizeF /// /// Width. /// Height. + /// and/or is negative. public GraphvizSizeF(float width, float height) { if (width < 0.0 || height < 0.0) @@ -114,9 +115,10 @@ public struct GraphvizSize /// /// Width. /// Height. + /// and/or is negative. public GraphvizSize(int width, int height) { - if (width < 0.0 || height < 0.0) + if (width < 0 || height < 0) throw new ArgumentException("Width and height must be positive or 0."); Width = width; diff --git a/src/QuikGraph.Graphviz/Events/FormatClusterEventArgs.cs b/src/QuikGraph.Graphviz/Events/FormatClusterEventArgs.cs index e02975fe9..962a57c08 100644 --- a/src/QuikGraph.Graphviz/Events/FormatClusterEventArgs.cs +++ b/src/QuikGraph.Graphviz/Events/FormatClusterEventArgs.cs @@ -18,6 +18,8 @@ public class FormatClusterEventArgs : EventArgs /// /// Graph to format. /// Graph format. + /// is . + /// is . public FormatClusterEventArgs([NotNull] IVertexAndEdgeListGraph clusteredGraph, [NotNull] GraphvizGraph graphFormat) { Cluster = clusteredGraph ?? throw new ArgumentNullException(nameof(clusteredGraph)); diff --git a/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs b/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs index ec7f943d2..a4c83a27c 100644 --- a/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs +++ b/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs @@ -8,7 +8,7 @@ namespace QuikGraph.Graphviz { /// - /// Helper extensions to render graphs to graphviz + /// Helper extensions to render graphs to graphviz. /// public static class GraphvizExtensions { @@ -19,6 +19,7 @@ public static class GraphvizExtensions /// Edge type. /// Graph to convert. /// Graph serialized in DOT format. + /// is . [Pure] [NotNull] public static string ToGraphviz([NotNull] this IEdgeListGraph graph) @@ -36,6 +37,8 @@ public static string ToGraphviz([NotNull] this IEdgeListGraphGraph to convert. /// Delegate that initializes the DOT generation algorithm. /// Graph serialized in DOT format. + /// is . + /// is . [Pure] [NotNull] public static string ToGraphviz( @@ -67,6 +70,7 @@ public static string ToGraphviz( /// Edge type. /// Graph to convert. /// The svg graph. + /// is . [Pure] [NotNull] public static string ToSvg([NotNull] this IEdgeListGraph graph) @@ -85,6 +89,8 @@ public static string ToSvg([NotNull] this IEdgeListGraphGraph to convert. /// Delegate that initializes the DOT generation algorithm. /// The svg graph. + /// is . + /// is . [Pure] [NotNull] public static string ToSvg( @@ -101,6 +107,7 @@ public static string ToSvg( /// /// The dot graph /// The svg graph. + /// is . [Pure] [NotNull] public static string ToSvg([NotNull] string dot) diff --git a/src/QuikGraph.Graphviz/FileDotEngine.cs b/src/QuikGraph.Graphviz/FileDotEngine.cs index 9adf627db..dfef0927b 100644 --- a/src/QuikGraph.Graphviz/FileDotEngine.cs +++ b/src/QuikGraph.Graphviz/FileDotEngine.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using QuikGraph.Graphviz.Dot; @@ -19,7 +19,9 @@ public string Run(GraphvizImageType imageType, string dot, string outputFilePath string output = outputFilePath; if (!output.EndsWith(".dot", StringComparison.OrdinalIgnoreCase)) + { output += ".dot"; + } File.WriteAllText(output, dot); return output; diff --git a/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs b/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs index 0ba0142af..a6aee85dc 100644 --- a/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs +++ b/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs @@ -22,6 +22,7 @@ public class GraphvizAlgorithm /// Initializes a new instance of the class. /// /// Graph to convert to DOT. + /// is . public GraphvizAlgorithm([NotNull] IEdgeListGraph graph) : this(graph, GraphvizImageType.Png) { @@ -32,6 +33,7 @@ public GraphvizAlgorithm([NotNull] IEdgeListGraph graph) /// /// Graph to convert to DOT. /// Target output image type. + /// is . public GraphvizAlgorithm( [NotNull] IEdgeListGraph graph, GraphvizImageType imageType) @@ -68,6 +70,7 @@ public GraphvizAlgorithm( /// /// Graph to convert. /// + /// Set value is . [NotNull] public IEdgeListGraph VisitedGraph { @@ -105,7 +108,9 @@ private void OnFormatCluster([NotNull] IVertexAndEdgeListGraph c formatCluster(this, args); string dot = args.GraphFormat.ToDot(); if (dot.Length != 0) + { Output.WriteLine(dot); + } } /// @@ -126,7 +131,9 @@ private void OnFormatVertex([NotNull] TVertex vertex) string dot = vertexFormat.InternalToDot(CommonVertexFormat); if (dot.Length != 0) + { Output.Write($" [{dot}]"); + } } Output.WriteLine(";"); } @@ -148,7 +155,9 @@ private void OnFormatEdge([NotNull] TEdge edge) string dot = edgeFormat.ToDot(); if (dot.Length != 0) + { Output.Write($" [{dot}]"); + } } Output.WriteLine(";"); } @@ -177,13 +186,19 @@ public string Generate() string graphFormat = GraphFormat.ToDot(); if (graphFormat.Length > 0) + { Output.WriteLine(graphFormat); + } string vertexFormat = CommonVertexFormat.ToDot(); if (vertexFormat.Length > 0) + { Output.WriteLine($"node [{vertexFormat}];"); + } string edgeFormat = CommonEdgeFormat.ToDot(); if (edgeFormat.Length > 0) + { Output.WriteLine($"edge [{edgeFormat}];"); + } // Initialize vertices map var verticesColors = new Dictionary(); @@ -215,6 +230,8 @@ public string Generate() /// and puts result in . /// /// File path containing DOT serialization of . + /// is . + /// is or empty. [NotNull] public string Generate([NotNull] IDotEngine dot, [NotNull] string outputFilePath) { diff --git a/src/QuikGraph.Graphviz/Helpers/DotEscapers.cs b/src/QuikGraph.Graphviz/Helpers/DotEscapers.cs index db7c138b2..8995cada9 100644 --- a/src/QuikGraph.Graphviz/Helpers/DotEscapers.cs +++ b/src/QuikGraph.Graphviz/Helpers/DotEscapers.cs @@ -1,4 +1,4 @@ -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using JetBrains.Annotations; namespace QuikGraph.Graphviz @@ -38,6 +38,7 @@ public static class DotEscapers /// /// String value to escape. /// Escaped string. + /// is . [Pure] [NotNull] public static string EscapePort([NotNull] string value) @@ -52,6 +53,7 @@ public static string EscapePort([NotNull] string value) /// /// String value to escape. /// Escaped string. + /// is . [Pure] [NotNull] public static string EscapeRecord([NotNull] string value) @@ -68,6 +70,7 @@ public static string EscapeRecord([NotNull] string value) /// /// String value to escape. /// Escaped string. + /// is . [Pure] [NotNull] public static string Escape([NotNull] string value) diff --git a/src/QuikGraph.Graphviz/Helpers/HtmlString.cs b/src/QuikGraph.Graphviz/Helpers/HtmlString.cs index 50c12c0be..bc129c065 100644 --- a/src/QuikGraph.Graphviz/Helpers/HtmlString.cs +++ b/src/QuikGraph.Graphviz/Helpers/HtmlString.cs @@ -11,6 +11,7 @@ internal struct HtmlString /// Initializes a new instance of the struct. /// /// HTML string. + /// is . public HtmlString([NotNull] string html) { String = html; diff --git a/src/QuikGraph.Graphviz/Interfaces/IDotEngine.cs b/src/QuikGraph.Graphviz/Interfaces/IDotEngine.cs index b7e2025c1..7a6355037 100644 --- a/src/QuikGraph.Graphviz/Interfaces/IDotEngine.cs +++ b/src/QuikGraph.Graphviz/Interfaces/IDotEngine.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; using QuikGraph.Graphviz.Dot; namespace QuikGraph.Graphviz @@ -16,6 +16,8 @@ public interface IDotEngine /// Graph serialized using Dot language. /// Target file path. /// Path to the saved result. + /// is or empty. + /// is or empty. [NotNull] string Run( GraphvizImageType imageType, diff --git a/src/QuikGraph.Graphviz/Renderers/CondensatedGraphRenderer.cs b/src/QuikGraph.Graphviz/Renderers/CondensatedGraphRenderer.cs index 0370f21be..133bea225 100644 --- a/src/QuikGraph.Graphviz/Renderers/CondensatedGraphRenderer.cs +++ b/src/QuikGraph.Graphviz/Renderers/CondensatedGraphRenderer.cs @@ -18,6 +18,7 @@ public class CondensatedGraphRenderer : GraphRendererBas /// Initializes a new instance of the class. /// /// Graph to convert to DOT. + /// is . public CondensatedGraphRenderer( [NotNull] IEdgeListGraph> graph) : base(graph) diff --git a/src/QuikGraph.Graphviz/Renderers/EdgeMergeCondensatedGraphRenderer.cs b/src/QuikGraph.Graphviz/Renderers/EdgeMergeCondensatedGraphRenderer.cs index 815a1d3f2..790da218e 100644 --- a/src/QuikGraph.Graphviz/Renderers/EdgeMergeCondensatedGraphRenderer.cs +++ b/src/QuikGraph.Graphviz/Renderers/EdgeMergeCondensatedGraphRenderer.cs @@ -16,6 +16,7 @@ public class EdgeMergeCondensatedGraphRenderer : GraphRendererBa /// Initializes a new instance of the class. /// /// Graph to convert to DOT. + /// is . public EdgeMergeCondensatedGraphRenderer( [NotNull] IEdgeListGraph> graph) : base(graph) diff --git a/src/QuikGraph.Graphviz/Renderers/GraphRendererBase.cs b/src/QuikGraph.Graphviz/Renderers/GraphRendererBase.cs index 428877c88..ad4ffc324 100644 --- a/src/QuikGraph.Graphviz/Renderers/GraphRendererBase.cs +++ b/src/QuikGraph.Graphviz/Renderers/GraphRendererBase.cs @@ -17,6 +17,7 @@ public abstract class GraphRendererBase /// Initializes a new instance of the class. /// /// Graph to convert to DOT. + /// is . protected GraphRendererBase([NotNull] IEdgeListGraph graph) { Graphviz = new GraphvizAlgorithm(graph); diff --git a/src/QuikGraph.MSAGL/Events/MsaglEdgeEventArgs.cs b/src/QuikGraph.MSAGL/Events/MsaglEdgeEventArgs.cs index 923554072..d0f658545 100644 --- a/src/QuikGraph.MSAGL/Events/MsaglEdgeEventArgs.cs +++ b/src/QuikGraph.MSAGL/Events/MsaglEdgeEventArgs.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; using Microsoft.Msagl.Drawing; @@ -17,7 +17,9 @@ public class MsaglEdgeEventArgs : EdgeEventArgs /// Initializes a new instance of the class. /// /// Concerned edge. - /// Concerned . + /// Concerned . + /// is . + /// is . public MsaglEdgeEventArgs([NotNull] TEdge edge, [NotNull] Edge msaglEdge) : base(edge) { @@ -25,7 +27,7 @@ public MsaglEdgeEventArgs([NotNull] TEdge edge, [NotNull] Edge msaglEdge) } /// - /// Edge concerned by the event. + /// concerned by the event. /// [NotNull] public Edge MsaglEdge { get; } diff --git a/src/QuikGraph.MSAGL/Events/MsaglVertexEventArgs.cs b/src/QuikGraph.MSAGL/Events/MsaglVertexEventArgs.cs index a580ae6a3..809fc7da8 100644 --- a/src/QuikGraph.MSAGL/Events/MsaglVertexEventArgs.cs +++ b/src/QuikGraph.MSAGL/Events/MsaglVertexEventArgs.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; using Microsoft.Msagl.Drawing; @@ -15,7 +15,9 @@ public class MsaglVertexEventArgs : VertexEventArgs /// Initializes a new instance of the class. /// /// Concerned vertex. - /// Concerned . + /// Concerned . + /// is . + /// is . public MsaglVertexEventArgs([NotNull] TVertex vertex, [NotNull] Node node) : base(vertex) { @@ -23,7 +25,7 @@ public MsaglVertexEventArgs([NotNull] TVertex vertex, [NotNull] Node node) } /// - /// concerned by the event. + /// concerned by the event. /// [NotNull] public Node Node { get; } diff --git a/src/QuikGraph.MSAGL/MsaglDefaultGraphPopulator.cs b/src/QuikGraph.MSAGL/MsaglDefaultGraphPopulator.cs index dd08b2385..e9d60c2d8 100644 --- a/src/QuikGraph.MSAGL/MsaglDefaultGraphPopulator.cs +++ b/src/QuikGraph.MSAGL/MsaglDefaultGraphPopulator.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -20,6 +20,7 @@ public class MsaglDefaultGraphPopulator : MsaglGraphPopulator class. /// /// Graph to convert to MSAGL graph. + /// is . public MsaglDefaultGraphPopulator([NotNull] IEdgeListGraph visitedGraph) : base(visitedGraph) { @@ -41,7 +42,7 @@ protected override void OnFinished(EventArgs args) Debug.Assert(args != null); _verticesIds = null; - + base.OnFinished(args); } diff --git a/src/QuikGraph.MSAGL/MsaglGraphExtensions.cs b/src/QuikGraph.MSAGL/MsaglGraphExtensions.cs index cea6b4129..04fedcc7d 100644 --- a/src/QuikGraph.MSAGL/MsaglGraphExtensions.cs +++ b/src/QuikGraph.MSAGL/MsaglGraphExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; using Microsoft.Msagl.Drawing; @@ -16,6 +16,7 @@ public static class MsaglGraphExtensions /// Edge type. /// Graph to convert to MSAGL graph. /// Graph populator. + /// is . public static MsaglGraphPopulator CreateMsaglPopulator( [NotNull] this IEdgeListGraph graph) where TEdge : IEdge @@ -32,6 +33,7 @@ public static MsaglGraphPopulator CreateMsaglPopulatorGraph format. /// Graph format provider. /// Graph populator. + /// is . public static MsaglGraphPopulator CreateMsaglPopulator( [NotNull] this IEdgeListGraph graph, [CanBeNull] string format, @@ -40,7 +42,7 @@ public static MsaglGraphPopulator CreateMsaglPopulator(graph, format, formatProvider); } - + /// /// Creates an . /// @@ -49,6 +51,8 @@ public static MsaglGraphPopulator CreateMsaglPopulatorGraph to convert to MSAGL graph. /// Delegate that given a vertex return its identifier. /// Graph populator. + /// is . + /// is . public static MsaglGraphPopulator CreateMsaglPopulator( [NotNull] this IEdgeListGraph graph, [NotNull] VertexIdentity vertexIdentity) @@ -58,7 +62,7 @@ public static MsaglGraphPopulator CreateMsaglPopulator - /// Converts to an . + /// Converts to an . /// /// Vertex type. /// Edge type. @@ -66,6 +70,7 @@ public static MsaglGraphPopulator CreateMsaglPopulatorNode added delegate. /// Edge added delegate. /// MSAGL Graph. + /// is . public static Graph ToMsaglGraph( [NotNull] this IEdgeListGraph graph, [CanBeNull] MsaglVertexNodeEventHandler nodeAdded = null, @@ -76,9 +81,14 @@ public static Graph ToMsaglGraph( try { if (nodeAdded != null) + { populator.NodeAdded += nodeAdded; + } + if (edgeAdded != null) + { populator.EdgeAdded += edgeAdded; + } populator.Compute(); return populator.MsaglGraph; @@ -86,14 +96,19 @@ public static Graph ToMsaglGraph( finally { if (nodeAdded != null) + { populator.NodeAdded -= nodeAdded; + } + if (edgeAdded != null) + { populator.EdgeAdded -= edgeAdded; + } } } /// - /// Converts to an . + /// Converts to an . /// /// Vertex type. /// Edge type. @@ -102,6 +117,8 @@ public static Graph ToMsaglGraph( /// Node added delegate. /// Edge added delegate. /// MSAGL Graph. + /// is . + /// is . public static Graph ToMsaglGraph( [NotNull] this IEdgeListGraph graph, [NotNull] VertexIdentity vertexIdentity, @@ -113,9 +130,14 @@ public static Graph ToMsaglGraph( try { if (nodeAdded != null) + { populator.NodeAdded += nodeAdded; + } + if (edgeAdded != null) + { populator.EdgeAdded += edgeAdded; + } populator.Compute(); return populator.MsaglGraph; @@ -123,9 +145,14 @@ public static Graph ToMsaglGraph( finally { if (nodeAdded != null) + { populator.NodeAdded -= nodeAdded; + } + if (edgeAdded != null) + { populator.EdgeAdded -= edgeAdded; + } } } } diff --git a/src/QuikGraph.MSAGL/MsaglGraphPopulator.cs b/src/QuikGraph.MSAGL/MsaglGraphPopulator.cs index 3b6431118..058a020d0 100644 --- a/src/QuikGraph.MSAGL/MsaglGraphPopulator.cs +++ b/src/QuikGraph.MSAGL/MsaglGraphPopulator.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using JetBrains.Annotations; using Microsoft.Msagl.Drawing; using QuikGraph.Algorithms; @@ -17,6 +17,7 @@ public abstract class MsaglGraphPopulator : AlgorithmBase class. /// /// Graph to convert to MSAGL graph. + /// is . protected MsaglGraphPopulator([NotNull] IEdgeListGraph visitedGraph) : base(visitedGraph) { @@ -35,7 +36,7 @@ protected MsaglGraphPopulator([NotNull] IEdgeListGraph visitedGr public event MsaglVertexNodeEventHandler NodeAdded; /// - /// Called when a is added. + /// Called when a is added. /// /// Event arguments. protected virtual void OnNodeAdded([NotNull] MsaglVertexEventArgs args) @@ -51,7 +52,7 @@ protected virtual void OnNodeAdded([NotNull] MsaglVertexEventArgs args) public event MsaglEdgeEventHandler EdgeAdded; /// - /// Called when an is added. + /// Called when an is added. /// /// Event arguments. protected virtual void OnEdgeAdded([NotNull] MsaglEdgeEventArgs args) @@ -94,14 +95,16 @@ protected override void InternalCompute() /// Called when a should be added to the graph. /// /// Vertex to add. - /// Added . + /// Added . + /// is . protected abstract Node AddNode([NotNull] TVertex vertex); /// /// Called when an should be added to the graph. /// /// Edge to add. - /// Added . + /// Added . + /// is . protected abstract Edge AddEdge([NotNull] TEdge edge); } } \ No newline at end of file diff --git a/src/QuikGraph.MSAGL/MsaglIdentifiableGraphPopulator.cs b/src/QuikGraph.MSAGL/MsaglIdentifiableGraphPopulator.cs index 29db73400..01092da9e 100644 --- a/src/QuikGraph.MSAGL/MsaglIdentifiableGraphPopulator.cs +++ b/src/QuikGraph.MSAGL/MsaglIdentifiableGraphPopulator.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; using Microsoft.Msagl.Drawing; @@ -20,6 +20,8 @@ public sealed class MsaglIdentifiableGraphPopulator : MsaglGraph /// /// Graph to convert to MSAGL graph. /// Delegate that given a vertex return its identifier. + /// is . + /// is . public MsaglIdentifiableGraphPopulator( [NotNull] IEdgeListGraph visitedGraph, [NotNull] VertexIdentity vertexIdentity) diff --git a/src/QuikGraph.MSAGL/MsaglToStringGraphPopulator.cs b/src/QuikGraph.MSAGL/MsaglToStringGraphPopulator.cs index 9adc6625d..8c92cd5f8 100644 --- a/src/QuikGraph.MSAGL/MsaglToStringGraphPopulator.cs +++ b/src/QuikGraph.MSAGL/MsaglToStringGraphPopulator.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.MSAGL @@ -17,6 +17,7 @@ public sealed class MsaglToStringGraphPopulator : MsaglDefaultGr /// Graph to convert to MSAGL graph. /// Graph format provider. /// Graph format. + /// is . public MsaglToStringGraphPopulator( [NotNull] IEdgeListGraph visitedGraph, [CanBeNull] string format = null, diff --git a/src/QuikGraph.Petri/Interfaces/IExpression.cs b/src/QuikGraph.Petri/Interfaces/IExpression.cs index ed199f9ad..91e013cdf 100644 --- a/src/QuikGraph.Petri/Interfaces/IExpression.cs +++ b/src/QuikGraph.Petri/Interfaces/IExpression.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph.Petri @@ -12,6 +12,7 @@ public interface IExpression /// /// Evaluates . /// + /// is . [NotNull, ItemNotNull] IList Evaluate([NotNull, ItemNotNull] IList markings); } diff --git a/src/QuikGraph.Petri/Interfaces/IMutablePetriNet.cs b/src/QuikGraph.Petri/Interfaces/IMutablePetriNet.cs index 1ac039f55..8706e95aa 100644 --- a/src/QuikGraph.Petri/Interfaces/IMutablePetriNet.cs +++ b/src/QuikGraph.Petri/Interfaces/IMutablePetriNet.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph.Petri { @@ -13,32 +13,38 @@ public interface IMutablePetriNet : IPetriNet /// /// Place name. /// Added . + /// is . [NotNull] IPlace AddPlace([NotNull] string name); - + /// /// Adds a with given to this Petri net. /// /// Transition name. /// Added . + /// is . [NotNull] ITransition AddTransition([NotNull] string name); - + /// /// Adds an with given source and target to this Petri net. /// /// Source place. /// Target transition. /// Added . + /// is . + /// is . [NotNull] IArc AddArc([NotNull] IPlace place, [NotNull] ITransition transition); - + /// /// Adds an with given source and target to this Petri net. /// /// Source transition. /// Target place. /// Added . + /// is . + /// is . [NotNull] IArc AddArc([NotNull] ITransition transition, [NotNull] IPlace place); } diff --git a/src/QuikGraph.Petri/Interfaces/IPetriVertex.cs b/src/QuikGraph.Petri/Interfaces/IPetriVertex.cs index 42d679485..03b1c5505 100644 --- a/src/QuikGraph.Petri/Interfaces/IPetriVertex.cs +++ b/src/QuikGraph.Petri/Interfaces/IPetriVertex.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph.Petri { @@ -11,7 +11,7 @@ public interface IPetriVertex /// Gets or sets the name of the node. /// /// - /// A representing the name of the node. + /// A representing the name of the node. /// [NotNull] string Name { get; } diff --git a/src/QuikGraph.Petri/PetriNetSimulator.cs b/src/QuikGraph.Petri/PetriNetSimulator.cs index 899b9afdd..ea9756648 100644 --- a/src/QuikGraph.Petri/PetriNetSimulator.cs +++ b/src/QuikGraph.Petri/PetriNetSimulator.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -21,6 +21,7 @@ public sealed class PetriNetSimulator /// Initializes a new instance of the class. /// /// Petri net to simulate. + /// is . public PetriNetSimulator([NotNull] IPetriNet net) { Net = net ?? throw new ArgumentNullException(nameof(net)); diff --git a/src/QuikGraph.Petri/Structures/Arc.cs b/src/QuikGraph.Petri/Structures/Arc.cs index ee8a59012..c8a1f5508 100644 --- a/src/QuikGraph.Petri/Structures/Arc.cs +++ b/src/QuikGraph.Petri/Structures/Arc.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Petri @@ -13,6 +13,8 @@ internal sealed class Arc : Edge, IArc /// /// Place (Source). /// Transition (Target). + /// is . + /// is . public Arc([NotNull] IPlace place, [NotNull] ITransition transition) : base(place, transition) { @@ -26,6 +28,8 @@ public Arc([NotNull] IPlace place, [NotNull] ITransition transit /// /// Transition (Source). /// Place (Target). + /// is . + /// is . public Arc([NotNull] ITransition transition, [NotNull] IPlace place) : base(place, transition) { @@ -47,6 +51,7 @@ public Arc([NotNull] ITransition transition, [NotNull] IPlace pl private IExpression _annotation = new IdentityExpression(); /// + /// Set value is . public IExpression Annotation { get => _annotation; diff --git a/src/QuikGraph.Petri/Structures/PetriNet.cs b/src/QuikGraph.Petri/Structures/PetriNet.cs index c0c74b0f1..80a4219f1 100644 --- a/src/QuikGraph.Petri/Structures/PetriNet.cs +++ b/src/QuikGraph.Petri/Structures/PetriNet.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE +#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE using System; #endif using System.Collections.Generic; @@ -31,6 +31,7 @@ public PetriNet() /// /// Copy constructor. /// + /// is . private PetriNet([NotNull] PetriNet other) { Debug.Assert(other != null); diff --git a/src/QuikGraph.Petri/Structures/Place.cs b/src/QuikGraph.Petri/Structures/Place.cs index 40976fbd1..1aa232ea9 100644 --- a/src/QuikGraph.Petri/Structures/Place.cs +++ b/src/QuikGraph.Petri/Structures/Place.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -18,6 +18,7 @@ internal sealed class Place : IPlace /// Initializes a new instance of the class. /// /// Place name. + /// is . public Place([NotNull] string name) { Name = name ?? throw new ArgumentNullException(nameof(name)); diff --git a/src/QuikGraph.Petri/Structures/Transition.cs b/src/QuikGraph.Petri/Structures/Transition.cs index 297ef3d57..003ea0725 100644 --- a/src/QuikGraph.Petri/Structures/Transition.cs +++ b/src/QuikGraph.Petri/Structures/Transition.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Petri @@ -12,6 +12,7 @@ internal sealed class Transition : ITransition /// Initializes a new instance of the class. /// /// Transition name. + /// is . public Transition([NotNull] string name) { Name = name ?? throw new ArgumentNullException(nameof(name)); @@ -24,6 +25,7 @@ public Transition([NotNull] string name) private IConditionExpression _condition = new AlwaysTrueConditionExpression(); /// + /// Set value is . public IConditionExpression Condition { get => _condition; diff --git a/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs b/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs index 3a31f87b4..a32fa5237 100644 --- a/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs +++ b/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -27,15 +27,18 @@ public sealed class DirectedGraphMLAlgorithm : AlgorithmBase /// Graph to visit. /// Vertex identity method. - /// Edge identity method. + /// Edge identity method. + /// is . + /// is . + /// is . public DirectedGraphMLAlgorithm( [NotNull] IVertexAndEdgeListGraph visitedGraph, [NotNull] VertexIdentity vertexIdentity, - [NotNull] EdgeIdentity edgeIdentities) + [NotNull] EdgeIdentity edgeIdentity) : base(visitedGraph) { _vertexIdentity = vertexIdentity ?? throw new ArgumentNullException(nameof(vertexIdentity)); - _edgeIdentity = edgeIdentities ?? throw new ArgumentNullException(nameof(edgeIdentities)); + _edgeIdentity = edgeIdentity ?? throw new ArgumentNullException(nameof(edgeIdentity)); } /// diff --git a/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs b/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs index 48738d8e9..3b586c5fd 100644 --- a/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs +++ b/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.IO; using System.Xml; @@ -29,20 +29,26 @@ public static class DirectedGraphMLExtensions /// /// Graph instance to write. /// Path to the file to write into. + /// is . + /// is . public static void WriteXml([NotNull] this DirectedGraph graph, [NotNull] string filePath) { if (string.IsNullOrEmpty(filePath)) throw new ArgumentException("Must provide a file path.", nameof(filePath)); using (StreamWriter stream = File.CreateText(filePath)) + { WriteXml(graph, stream); + } } /// - /// Writes the DGML data structure to the . + /// Writes the DGML data structure to the . /// /// Graph instance to write. /// XML writer in which writing graph data. + /// is . + /// is . public static void WriteXml([NotNull] this DirectedGraph graph, [NotNull] XmlWriter writer) { if (graph is null) @@ -54,10 +60,12 @@ public static void WriteXml([NotNull] this DirectedGraph graph, [NotNull] XmlWri } /// - /// Writes the DGML data structure to the . + /// Writes the DGML data structure to the . /// /// Graph instance to write. /// Stream in which writing graph data. + /// is . + /// is . public static void WriteXml([NotNull] this DirectedGraph graph, [NotNull] Stream stream) { if (graph is null) @@ -69,10 +77,12 @@ public static void WriteXml([NotNull] this DirectedGraph graph, [NotNull] Stream } /// - /// Writes the DGML data structure to the . + /// Writes the DGML data structure to the . /// /// Graph instance to write. /// Text writer in which writing graph data. + /// is . + /// is . public static void WriteXml([NotNull] this DirectedGraph graph, [NotNull] TextWriter writer) { if (graph is null) @@ -88,18 +98,19 @@ public static void WriteXml([NotNull] this DirectedGraph graph, [NotNull] TextWr /// /// Vertex type. /// Edge type. - /// Graph to convert to . + /// Graph to convert to . /// Converted graph. + /// is . [Pure] [NotNull] public static DirectedGraph ToDirectedGraphML( - [NotNull] this IVertexAndEdgeListGraph visitedGraph) + [NotNull] this IVertexAndEdgeListGraph graph) where TEdge : IEdge { return ToDirectedGraphML( - visitedGraph, - visitedGraph.GetVertexIdentity(), - visitedGraph.GetEdgeIdentity()); + graph, + graph.GetVertexIdentity(), + graph.GetEdgeIdentity()); } /// @@ -107,26 +118,28 @@ public static DirectedGraph ToDirectedGraphML( /// /// Vertex type. /// Edge type. - /// Graph to convert to . - /// Function that gives the color of a vertex. + /// Graph to convert to . + /// Function that gives the color of a vertex. /// Converted graph. + /// is . + /// is . [Pure] [NotNull] public static DirectedGraph ToDirectedGraphML( - [NotNull] this IVertexAndEdgeListGraph visitedGraph, - [NotNull] Func vertexColors) + [NotNull] this IVertexAndEdgeListGraph graph, + [NotNull] Func verticesColors) where TEdge : IEdge { - if (vertexColors is null) - throw new ArgumentNullException(nameof(vertexColors)); + if (verticesColors is null) + throw new ArgumentNullException(nameof(verticesColors)); return ToDirectedGraphML( - visitedGraph, - visitedGraph.GetVertexIdentity(), - visitedGraph.GetEdgeIdentity(), + graph, + graph.GetVertexIdentity(), + graph.GetEdgeIdentity(), (vertex, node) => { - GraphColor color = vertexColors(vertex); + GraphColor color = verticesColors(vertex); switch (color) { case GraphColor.Black: @@ -148,20 +161,23 @@ public static DirectedGraph ToDirectedGraphML( /// /// Vertex type. /// Edge type. - /// Graph to convert to . + /// Graph to convert to . /// Vertex identity method. /// Edge identity method. /// Converted graph. + /// is . + /// is . + /// is . [Pure] [NotNull] public static DirectedGraph ToDirectedGraphML( - [NotNull] this IVertexAndEdgeListGraph visitedGraph, + [NotNull] this IVertexAndEdgeListGraph graph, [NotNull] VertexIdentity vertexIdentity, [NotNull] EdgeIdentity edgeIdentity) where TEdge : IEdge { return ToDirectedGraphML( - visitedGraph, + graph, vertexIdentity, edgeIdentity, null, @@ -173,16 +189,19 @@ public static DirectedGraph ToDirectedGraphML( /// /// Vertex type. /// Edge type. - /// Graph to convert to . + /// Graph to convert to . /// Vertex identity method. /// Edge identity method. /// Formats a vertex into a . /// Formats an edge into a . /// Converted graph. + /// is . + /// is . + /// is . [Pure] [NotNull] public static DirectedGraph ToDirectedGraphML( - [NotNull] this IVertexAndEdgeListGraph visitedGraph, + [NotNull] this IVertexAndEdgeListGraph graph, [NotNull] VertexIdentity vertexIdentity, [NotNull] EdgeIdentity edgeIdentity, [CanBeNull] Action formatNode, @@ -190,14 +209,20 @@ public static DirectedGraph ToDirectedGraphML( where TEdge : IEdge { var algorithm = new DirectedGraphMLAlgorithm( - visitedGraph, + graph, vertexIdentity, edgeIdentity); if (formatNode != null) + { algorithm.FormatNode += formatNode; + } + if (formatEdge != null) + { algorithm.FormatEdge += formatEdge; + } + algorithm.Compute(); return algorithm.DirectedGraph; @@ -210,6 +235,7 @@ public static DirectedGraph ToDirectedGraphML( /// Edge type. /// Graph to open. /// Path to the file to save. + /// is . public static void OpenAsDGML( [NotNull] this IVertexAndEdgeListGraph graph, [CanBeNull] string filePath) @@ -219,7 +245,9 @@ public static void OpenAsDGML( throw new ArgumentNullException(nameof(graph)); if (filePath is null) + { filePath = "graph.DGML"; + } graph.ToDirectedGraphML().WriteXml(filePath); diff --git a/src/QuikGraph.Serialization/GraphMLDeserializer.cs b/src/QuikGraph.Serialization/GraphMLDeserializer.cs index 8b9731e33..5ba033d36 100644 --- a/src/QuikGraph.Serialization/GraphMLDeserializer.cs +++ b/src/QuikGraph.Serialization/GraphMLDeserializer.cs @@ -22,7 +22,7 @@ namespace QuikGraph.Serialization /// /// /// Custom vertex, edge and graph attributes can be specified by - /// using the attribute on properties (field not supported). + /// using the attribute on properties (field not supported). /// /// /// The serializer uses LCG (lightweight code generation) to generate the @@ -253,6 +253,14 @@ private static Delegate CreateReadDelegate( /// Graph instance to fill. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// Deserializing value on property without setter, or with invalid default value. + /// or not found. + /// Failure while reading elements from GraphML. + /// Deserializing graph with unsupported property type. public void Deserialize( [NotNull] XmlReader reader, [NotNull] TGraph graph, @@ -345,13 +353,12 @@ private void ReadElements() var vertices = new Dictionary(StringComparer.Ordinal); // Read vertices or edges - XmlReader reader = _reader; - while (reader.Read()) + while (_reader.Read()) { - if (reader.NodeType == XmlNodeType.Element - && reader.NamespaceURI == _graphMLNamespace) + if (_reader.NodeType == XmlNodeType.Element + && _reader.NamespaceURI == _graphMLNamespace) { - switch (reader.Name) + switch (_reader.Name) { case NodeTag: ReadVertex(vertices); diff --git a/src/QuikGraph.Serialization/GraphMLExtensions.cs b/src/QuikGraph.Serialization/GraphMLExtensions.cs index 96190d497..3b943205b 100644 --- a/src/QuikGraph.Serialization/GraphMLExtensions.cs +++ b/src/QuikGraph.Serialization/GraphMLExtensions.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_GRAPHS_SERIALIZATION +#if SUPPORTS_GRAPHS_SERIALIZATION using System; #if SUPPORTS_XML_DTD_PROCESSING using System.Diagnostics; @@ -29,6 +29,10 @@ public static class GraphMLExtensions /// Graph type. /// Graph instance to serialize. /// Path to the file where serializing the graph. + /// is . + /// is or empty. + /// Failure while writing elements to GraphML. + /// Serializing value on property without getter, or with unsupported property type. public static void SerializeToGraphML( [NotNull] this TGraph graph, [NotNull] string filePath) @@ -56,6 +60,12 @@ public static void SerializeToGraphML( /// Path to the file where serializing the graph. /// Vertex identity method. /// Edge identity method. + /// is . + /// is . + /// is . + /// is or empty. + /// Failure while writing elements to GraphML. + /// Serializing value on property without getter, or with unsupported property type. public static void SerializeToGraphML( [NotNull] this TGraph graph, [NotNull] string filePath, @@ -83,6 +93,10 @@ public static void SerializeToGraphML( /// Graph type. /// Graph instance to serialize. /// The XML writer. + /// is . + /// is . + /// Failure while writing elements to GraphML. + /// Serializing value on property without getter, or with unsupported property type. public static void SerializeToGraphML( [NotNull] this TGraph graph, [NotNull] XmlWriter writer) @@ -108,6 +122,12 @@ public static void SerializeToGraphML( /// The XML writer. /// Vertex identity method. /// Edge identity method. + /// is . + /// is . + /// is . + /// is . + /// Failure while writing elements to GraphML. + /// Serializing value on property without getter, or with unsupported property type. public static void SerializeToGraphML( [NotNull] this TGraph graph, [NotNull] XmlWriter writer, @@ -134,6 +154,14 @@ public static void SerializeToGraphML( /// The XML reader. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// Deserializing value on property without setter, or with invalid default value. + /// or not found. + /// Failure while reading elements from GraphML. + /// Deserializing graph with unsupported property type. public static void DeserializeFromGraphML( [NotNull] this TGraph graph, [NotNull] XmlReader reader, @@ -156,6 +184,14 @@ public static void DeserializeFromGraphML( /// Reader stream. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// Deserializing value on property without setter, or with invalid default value. + /// or not found. + /// Failure while reading elements from GraphML. + /// Deserializing graph with unsupported property type. public static void DeserializeFromGraphML( [NotNull] this TGraph graph, [NotNull] TextReader reader, @@ -197,6 +233,14 @@ public static void DeserializeFromGraphML( /// Path to the file to load. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is or empty. + /// Deserializing value on property without setter, or with invalid default value. + /// or not found. + /// Failure while reading elements from GraphML. + /// Deserializing graph with unsupported property type. public static void DeserializeFromGraphML( [NotNull] this TGraph graph, [NotNull] string filePath, @@ -209,7 +253,9 @@ public static void DeserializeFromGraphML( throw new ArgumentException("Must provide a file path.", nameof(filePath)); using (var reader = new StreamReader(filePath)) + { DeserializeFromGraphML(graph, reader, vertexFactory, edgeFactory); + } } #if SUPPORTS_XML_DTD_PROCESSING @@ -224,6 +270,14 @@ public static void DeserializeFromGraphML( /// Reader stream. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// Deserializing value on property without setter, or with invalid default value. + /// or not found. + /// Failure while reading elements from GraphML. + /// Deserializing graph with unsupported property type. public static void DeserializeAndValidateFromGraphML( [NotNull] this TGraph graph, [NotNull] TextReader reader, @@ -258,7 +312,9 @@ public static void DeserializeAndValidateFromGraphML( // Read and validate using (XmlReader xmlReader = XmlReader.Create(reader, settings)) + { serializer.Deserialize(xmlReader, graph, vertexFactory, edgeFactory); + } } finally { @@ -273,8 +329,11 @@ private static void AddGraphMLSchema([NotNull] XmlReaderSettings settings, [NotN Debug.Assert(xsdStream != null, "GraphML schema resource not found."); settings.Schemas.XmlResolver = resolver; + // ReSharper disable once AssignNullToNotNullAttribute, Justification: assert above using (XmlReader xsdReader = XmlReader.Create(xsdStream, settings)) + { settings.Schemas.Add(GraphMLXmlResolver.GraphMLNamespace, xsdReader); + } } } diff --git a/src/QuikGraph.Serialization/GraphMLSerializer.cs b/src/QuikGraph.Serialization/GraphMLSerializer.cs index 45da0a008..0a55adbe3 100644 --- a/src/QuikGraph.Serialization/GraphMLSerializer.cs +++ b/src/QuikGraph.Serialization/GraphMLSerializer.cs @@ -21,7 +21,7 @@ namespace QuikGraph.Serialization /// /// /// Custom vertex, edge and graph attributes can be specified by - /// using the attribute on properties (field not supported). + /// using the attribute on properties (field not supported). /// /// /// The serializer uses LCG (lightweight code generation) to generate the @@ -187,6 +187,12 @@ private static Delegate CreateWriteDelegate([NotNull] Type elementType, [NotNull /// Graph instance to serialize. /// Vertex identity method. /// Edge identity method. + /// is . + /// is . + /// is . + /// is . + /// Failure while writing elements to GraphML. + /// Serializing value on property without getter, or with unsupported property type. public void Serialize( [NotNull] XmlWriter writer, [NotNull] TGraph graph, @@ -259,8 +265,10 @@ public void Serialize() private void WriteHeader() { if (_serializer.EmitDocumentDeclaration) + { _writer.WriteStartDocument(); - _writer.WriteStartElement("", GraphMLTag, GraphMLXmlResolver.GraphMLNamespace); + } + _writer.WriteStartElement(string.Empty, GraphMLTag, GraphMLXmlResolver.GraphMLNamespace); } private void WriteFooter() @@ -408,7 +416,7 @@ private void WriteAttributeDefinitions([NotNull] string elementName, [NotNull] T break; case TypeCode.Object: if (defaultValueType.IsArray) - throw new NotImplementedException("Default values for array types are not implemented."); + throw new NotSupportedException("Default values for array types are not supported."); throw new NotSupportedException( $"Property type {property.DeclaringType}.{property.Name} not supported by the GraphML schema."); default: diff --git a/src/QuikGraph.Serialization/GraphMLXmlResolver.cs b/src/QuikGraph.Serialization/GraphMLXmlResolver.cs index 45d2d4044..4f40f3337 100644 --- a/src/QuikGraph.Serialization/GraphMLXmlResolver.cs +++ b/src/QuikGraph.Serialization/GraphMLXmlResolver.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_GRAPHS_SERIALIZATION +#if SUPPORTS_GRAPHS_SERIALIZATION using System; using System.Diagnostics; using System.IO; @@ -29,6 +29,7 @@ public GraphMLXmlResolver() /// Initializes a new instance of the class. /// /// Base XML resolver. + /// is . public GraphMLXmlResolver([NotNull] XmlResolver baseResolver) { _baseResolver = baseResolver ?? throw new ArgumentNullException(nameof(baseResolver)); diff --git a/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs b/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs index 6e45c7fb2..27233df8d 100644 --- a/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs +++ b/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_GRAPHS_SERIALIZATION +#if SUPPORTS_GRAPHS_SERIALIZATION using System; using System.Collections.Generic; using System.Linq; @@ -39,8 +39,8 @@ private static bool IsIndexed([NotNull] PropertyInfo property) /// /// Gets all properties that are marked with on given type. /// - /// - /// + /// Object type. + /// Enumerable of serializable properties information. [Pure] [NotNull] public static IEnumerable GetAttributeProperties([CanBeNull] Type type) diff --git a/src/QuikGraph.Serialization/SerializationExtensions.cs b/src/QuikGraph.Serialization/SerializationExtensions.cs index deefc40a7..71c1cf496 100644 --- a/src/QuikGraph.Serialization/SerializationExtensions.cs +++ b/src/QuikGraph.Serialization/SerializationExtensions.cs @@ -23,6 +23,9 @@ public static class SerializationExtensions /// Edge type. /// The graph to serialize. /// Stream in which serializing the graph. + /// is . + /// is . + /// is not writable. public static void SerializeToBinary( [NotNull] this IGraph graph, [NotNull] Stream stream) @@ -48,13 +51,15 @@ public static void SerializeToBinary( /// Stream from which deserializing the graph. /// /// - /// used during deserialization. + /// used during deserialization. /// It can be used to check/filter/replace/upgrade types that are loaded. /// /// It is also useful in security scenarios. /// By default no binder is used. /// /// Deserialized graph. + /// is . + /// is not readable. [Pure] public static TGraph DeserializeFromBinary( [NotNull] this Stream stream, @@ -154,7 +159,7 @@ private static TGraph DeserializeFromXmlInternal( } /// - /// Deserializes a graph instance from a generic XML stream, using an . + /// Deserializes a graph instance from a generic XML stream, using an . /// /// Vertex type. /// Edge type. @@ -167,7 +172,14 @@ private static TGraph DeserializeFromXmlInternal( /// Delegate that instantiates a vertex instance, given the vertex node. /// Delegate that instantiates an edge instance, given the edge node. /// Deserialized graph. - /// + /// is . + /// is . + /// is or creates vertex. + /// is or creates edge. + /// is or empty. + /// is or empty. + /// is or empty. + /// /// If the does not allow to get an XML navigator /// or if the does not allow to get graph node. /// @@ -210,7 +222,7 @@ public static TGraph DeserializeFromXml( #endif /// - /// Deserializes a graph instance from a generic XML stream, using an . + /// Deserializes a graph instance from a generic XML stream, using an . /// /// Vertex type. /// Edge type. @@ -223,7 +235,14 @@ public static TGraph DeserializeFromXml( /// Delegate that instantiates a vertex instance, given the vertex node. /// Delegate that instantiates an edge instance, given the edge node. /// Deserialized graph. - /// If the graph node cannot be found. + /// is . + /// is . + /// is . + /// is . + /// is . + /// is or creates vertex. + /// is or creates edge. + /// If the graph node cannot be found. [Pure] public static TGraph DeserializeFromXml( [NotNull] this XmlReader reader, @@ -255,7 +274,7 @@ public static TGraph DeserializeFromXml( } /// - /// Deserializes a graph from a generic XML stream, using an . + /// Deserializes a graph from a generic XML stream, using an . /// /// Vertex type. /// Edge type. @@ -269,7 +288,15 @@ public static TGraph DeserializeFromXml( /// Delegate that instantiates a vertex instance, given the vertex node. /// Delegate that instantiates an edge instance, given the edge node. /// Deserialized graph. - /// If the graph node cannot be found. + /// is . + /// is . + /// is . + /// is or creates vertex. + /// is or creates edge. + /// is or empty. + /// is or empty. + /// is or empty. + /// If the graph node cannot be found. [Pure] public static TGraph DeserializeFromXml( [NotNull] this XmlReader reader, @@ -303,7 +330,7 @@ public static TGraph DeserializeFromXml( } /// - /// Serializes a graph instance to a generic XML stream, using an . + /// Serializes a graph instance to a generic XML stream, using an . /// /// Vertex type. /// Edge type. @@ -316,6 +343,14 @@ public static TGraph DeserializeFromXml( /// Name of the vertex element. /// Name of the edge element. /// XML namespace. + /// is . + /// is . + /// is . + /// is . + /// is . + /// is or empty. + /// is or empty. + /// is or empty. public static void SerializeToXml( [NotNull] this TGraph graph, [NotNull] XmlWriter writer, @@ -343,7 +378,7 @@ public static void SerializeToXml( } /// - /// Serializes a graph instance to a generic XML stream, using an . + /// Serializes a graph instance to a generic XML stream, using an . /// /// Vertex type. /// Edge type. @@ -359,6 +394,14 @@ public static void SerializeToXml( /// Delegate to write graph attributes (optional). /// Delegate to write vertex attributes (optional). /// Delegate to write edge attributes (optional). + /// is . + /// is . + /// is . + /// is . + /// is . + /// is or empty. + /// is or empty. + /// is or empty. public static void SerializeToXml( [NotNull] this TGraph graph, [NotNull] XmlWriter writer, diff --git a/src/QuikGraph.Serialization/XmlReaderExtensions.cs b/src/QuikGraph.Serialization/XmlReaderExtensions.cs index 8aaaece2e..39d7111e6 100644 --- a/src/QuikGraph.Serialization/XmlReaderExtensions.cs +++ b/src/QuikGraph.Serialization/XmlReaderExtensions.cs @@ -1,11 +1,11 @@ -using System; +using System; using System.Xml; using JetBrains.Annotations; namespace QuikGraph.Serialization { /// - /// Extensions for to help deserializing graph data. + /// Extensions for to help deserializing graph data. /// public static class XmlReaderExtensions { @@ -16,6 +16,9 @@ public static class XmlReaderExtensions /// Node name. /// XML namespace. /// Boolean array. + /// is . + /// is . + /// is empty. [Pure] [CanBeNull] public static bool[] ReadElementContentAsBooleanArray( @@ -33,6 +36,9 @@ public static bool[] ReadElementContentAsBooleanArray( /// Node name. /// XML namespace. /// Int array. + /// is . + /// is . + /// is empty. [Pure] [CanBeNull] public static int[] ReadElementContentAsInt32Array( @@ -50,6 +56,9 @@ public static int[] ReadElementContentAsInt32Array( /// Node name. /// XML namespace. /// Long array. + /// is . + /// is . + /// is empty. [Pure] [CanBeNull] public static long[] ReadElementContentAsInt64Array( @@ -67,6 +76,9 @@ public static long[] ReadElementContentAsInt64Array( /// Node name. /// XML namespace. /// Float array. + /// is . + /// is . + /// is empty. [Pure] [CanBeNull] public static float[] ReadElementContentAsSingleArray( @@ -84,6 +96,9 @@ public static float[] ReadElementContentAsSingleArray( /// Node name. /// XML namespace. /// Double array. + /// is . + /// is . + /// is empty. [Pure] [CanBeNull] public static double[] ReadElementContentAsDoubleArray( @@ -101,6 +116,9 @@ public static double[] ReadElementContentAsDoubleArray( /// Node name. /// XML namespace. /// String array. + /// is . + /// is . + /// is empty. [Pure] [CanBeNull] public static string[] ReadElementContentAsStringArray( @@ -120,6 +138,9 @@ public static string[] ReadElementContentAsStringArray( /// XML namespace. /// Converts the XML element string as . /// Array of . + /// is . + /// is . + /// is empty. [Pure] [CanBeNull] public static T[] ReadElementContentAsArray( diff --git a/src/QuikGraph.Serialization/XmlSerializableGraph.cs b/src/QuikGraph.Serialization/XmlSerializableGraph.cs index e828ca7b6..ff3693628 100644 --- a/src/QuikGraph.Serialization/XmlSerializableGraph.cs +++ b/src/QuikGraph.Serialization/XmlSerializableGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Xml.Serialization; @@ -32,6 +32,7 @@ public XmlSerializableGraph() /// Initializes a new instance of the class. /// /// Graph to serialize. + /// is . public XmlSerializableGraph([NotNull] TGraph graph) { if (graph == null) @@ -113,6 +114,7 @@ IEnumerator IEnumerable.GetEnumerator() /// Adds a vertex to this serializable graph. /// /// Vertex to add. + /// is . public void Add([NotNull] TVertex vertex) { if (vertex == null) @@ -161,6 +163,7 @@ IEnumerator IEnumerable.GetEnumerator() /// Adds an edge to this serializable graph. /// /// Edge to add. + /// is . public void Add([NotNull] TEdge edge) { if (edge == null) diff --git a/src/QuikGraph.Serialization/XmlWriterExtensions.cs b/src/QuikGraph.Serialization/XmlWriterExtensions.cs index 965127bf2..2c7b1c365 100644 --- a/src/QuikGraph.Serialization/XmlWriterExtensions.cs +++ b/src/QuikGraph.Serialization/XmlWriterExtensions.cs @@ -5,7 +5,7 @@ namespace QuikGraph.Serialization { /// - /// Extensions for to help serializing graph data. + /// Extensions for to help serializing graph data. /// public static class XmlWriterExtensions { diff --git a/src/QuikGraph/Algorithms/AlgorithmBase.cs b/src/QuikGraph/Algorithms/AlgorithmBase.cs index 229928b90..0e003732d 100644 --- a/src/QuikGraph/Algorithms/AlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/AlgorithmBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; #if SUPPORTS_AGGRESSIVE_INLINING @@ -23,13 +23,16 @@ public abstract class AlgorithmBase : IAlgorithm, IAlgorithmComp /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . protected AlgorithmBase([CanBeNull] IAlgorithmComponent host, [NotNull] TGraph visitedGraph) { if (visitedGraph == null) throw new ArgumentNullException(nameof(visitedGraph)); if (host is null) + { host = this; + } VisitedGraph = visitedGraph; _algorithmServices = new AlgorithmServices(host); } @@ -38,6 +41,7 @@ protected AlgorithmBase([CanBeNull] IAlgorithmComponent host, [NotNull] TGraph v /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . protected AlgorithmBase([NotNull] TGraph visitedGraph) { if (visitedGraph == null) @@ -67,6 +71,7 @@ public ComputationState State } /// + /// Something went wrong when running the algorithm. public void Compute() { BeginComputation(); @@ -104,7 +109,9 @@ public void Abort() } if (raise) + { OnStateChanged(EventArgs.Empty); + } } /// @@ -113,7 +120,7 @@ public void Abort() /// /// Called on algorithm state changed. /// - /// . + /// . protected virtual void OnStateChanged([NotNull] EventArgs args) { Debug.Assert(args != null); @@ -127,7 +134,7 @@ protected virtual void OnStateChanged([NotNull] EventArgs args) /// /// Called on algorithm start. /// - /// . + /// . protected virtual void OnStarted([NotNull] EventArgs args) { Debug.Assert(args != null); @@ -141,7 +148,7 @@ protected virtual void OnStarted([NotNull] EventArgs args) /// /// Called on algorithm finished. /// - /// . + /// . protected virtual void OnFinished([NotNull] EventArgs args) { Debug.Assert(args != null); @@ -155,7 +162,7 @@ protected virtual void OnFinished([NotNull] EventArgs args) /// /// Called on algorithm abort. /// - /// . + /// . protected virtual void OnAborted([NotNull] EventArgs args) { Debug.Assert(args != null); @@ -181,6 +188,7 @@ protected virtual void OnAborted([NotNull] EventArgs args) public IAlgorithmServices Services => _algorithmServices; /// + /// Requested service is not present on algorithm. public T GetService() { if (!TryGetService(out T service)) @@ -211,6 +219,7 @@ public bool TryGetService(out T service) /// Found service. /// True if the service was found, false otherwise. [Pure] + [ContractAnnotation("=> true, service:notnull;=> false, service:null")] protected virtual bool TryGetService([NotNull] Type serviceType, out object service) { if (serviceType is null) @@ -219,15 +228,21 @@ protected virtual bool TryGetService([NotNull] Type serviceType, out object serv lock (SyncRoot) { if (_services is null) + { _services = new Dictionary(); + } if (_services.TryGetValue(serviceType, out service)) return service != null; if (serviceType == typeof(ICancelManager)) + { _services[serviceType] = service = new CancelManager(); + } else + { _services[serviceType] = null; + } return service != null; } @@ -238,7 +253,7 @@ protected virtual bool TryGetService([NotNull] Type serviceType, out object serv /// /// Throws if a cancellation of the algorithm was requested. /// - /// + /// /// If the algorithm cancellation service indicates is true. /// #if SUPPORTS_AGGRESSIVE_INLINING diff --git a/src/QuikGraph/Algorithms/Assignment/HungarianAlgorithm.cs b/src/QuikGraph/Algorithms/Assignment/HungarianAlgorithm.cs index 1f8efbe80..e67b08e68 100644 --- a/src/QuikGraph/Algorithms/Assignment/HungarianAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Assignment/HungarianAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -72,6 +72,7 @@ public enum Steps /// Initializes a new instance of the class. /// /// Costs matrix. + /// is . public HungarianAlgorithm([NotNull] int[,] costs) { _costs = costs ?? throw new ArgumentNullException(nameof(costs)); @@ -135,27 +136,23 @@ private Steps ComputeStep(Steps step) { case Steps.Step1: { - Steps currentStep = step; _step = RunStep1(_masks, _colsCovered, _width, _height); - return currentStep; + return step; } case Steps.Step2: { - Steps currentStep = step; _step = RunStep2(_costs, _masks, _rowsCovered, _colsCovered, _width, _height, ref _pathStart); - return currentStep; + return step; } case Steps.Step3: { - Steps currentStep = step; _step = RunStep3(_masks, _rowsCovered, _colsCovered, _width, _height, _path, _pathStart); - return currentStep; + return step; } case Steps.Step4: { - Steps currentStep = step; _step = RunStep4(_costs, _rowsCovered, _colsCovered, _width, _height); - return currentStep; + return step; } } @@ -209,9 +206,14 @@ private Steps RunInitStep() { int min = int.MaxValue; for (int j = 0; j < _width; ++j) + { min = Math.Min(min, _costs[i, j]); + } + for (int j = 0; j < _width; ++j) + { _costs[i, j] -= min; + } } // Set 1 where job assigned @@ -237,7 +239,9 @@ private static Steps RunStep1( for (int j = 0; j < width; ++j) { if (masks[i, j] == 1) + { colsCovered[j] = true; + } } } @@ -245,7 +249,9 @@ private static Steps RunStep1( for (int j = 0; j < width; ++j) { if (colsCovered[j]) + { ++colsCoveredCount; + } } return colsCoveredCount == height ? Steps.End : Steps.Step2; @@ -326,9 +332,14 @@ private static Steps RunStep4( for (int j = 0; j < width; ++j) { if (rowsCovered[i]) + { costs[i, j] += minValue; + } + if (!colsCovered[j]) + { costs[i, j] -= minValue; + } } } @@ -386,7 +397,9 @@ private static int FindMinimum( for (int j = 0; j < width; ++j) { if (!rowsCovered[i] && !colsCovered[j]) + { minValue = Math.Min(minValue, costs[i, j]); + } } } @@ -442,9 +455,14 @@ private static void ClearCovers( int height) { for (int i = 0; i < height; ++i) + { rowsCovered[i] = false; + } + for (int j = 0; j < width; ++j) + { colsCovered[j] = false; + } } private static void ClearPrimes( @@ -457,7 +475,9 @@ private static void ClearPrimes( for (int j = 0; j < width; ++j) { if (masks[i, j] == 2) + { masks[i, j] = 0; + } } } } diff --git a/src/QuikGraph/Algorithms/Assignment/HungarianIteration.cs b/src/QuikGraph/Algorithms/Assignment/HungarianIteration.cs index 3b746469f..49596fb43 100644 --- a/src/QuikGraph/Algorithms/Assignment/HungarianIteration.cs +++ b/src/QuikGraph/Algorithms/Assignment/HungarianIteration.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using JetBrains.Annotations; namespace QuikGraph.Algorithms.Assignment @@ -46,6 +47,11 @@ internal HungarianIteration( [NotNull] bool[] columnsCovered, HungarianAlgorithm.Steps step) { + Debug.Assert(costs != null); + Debug.Assert(mask != null); + Debug.Assert(rowsCovered != null); + Debug.Assert(columnsCovered != null); + Matrix = costs; Mask = mask; RowsCovered = rowsCovered; diff --git a/src/QuikGraph/Algorithms/Cliques/MaximumCliqueAlgorithmBase.cs b/src/QuikGraph/Algorithms/Cliques/MaximumCliqueAlgorithmBase.cs index 5a1ca100d..c32170b2c 100644 --- a/src/QuikGraph/Algorithms/Cliques/MaximumCliqueAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/Cliques/MaximumCliqueAlgorithmBase.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION +#if SUPPORTS_SERIALIZATION using System; #endif using JetBrains.Annotations; @@ -22,6 +22,7 @@ public abstract class MaximumCliqueAlgorithmBase : AlgorithmBase /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . protected MaximumCliqueAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph) @@ -33,6 +34,7 @@ protected MaximumCliqueAlgorithmBase( /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . protected MaximumCliqueAlgorithmBase([NotNull] IUndirectedGraph visitedGraph) : base(visitedGraph) { diff --git a/src/QuikGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs b/src/QuikGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs index 18e6ac3c1..b781ca7c1 100644 --- a/src/QuikGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Condensation/CondensationGraphAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; using QuikGraph.Algorithms.ConnectedComponents; @@ -19,6 +19,7 @@ public sealed class CondensationGraphAlgorithm : Algorit /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public CondensationGraphAlgorithm([NotNull] IVertexAndEdgeListGraph visitedGraph) : base(visitedGraph) { diff --git a/src/QuikGraph/Algorithms/Condensation/CondensedEdge.cs b/src/QuikGraph/Algorithms/Condensation/CondensedEdge.cs index 0527a6db7..e1db4f687 100644 --- a/src/QuikGraph/Algorithms/Condensation/CondensedEdge.cs +++ b/src/QuikGraph/Algorithms/Condensation/CondensedEdge.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION +#if SUPPORTS_SERIALIZATION using System; #endif using System.Collections.Generic; @@ -24,6 +24,8 @@ public sealed class CondensedEdge : Edge /// /// The source graph. /// The target graph. + /// is . + /// is . public CondensedEdge([NotNull] TGraph source, [NotNull] TGraph target) : base(source, target) { diff --git a/src/QuikGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs b/src/QuikGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs index 58a997fce..d1a407706 100644 --- a/src/QuikGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Condensation/EdgeMergeCondensationGraphAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -19,6 +19,9 @@ public sealed class EdgeMergeCondensationGraphAlgorithm : Algori /// Graph to visit. /// Graph that will contains the condensation of the . /// Vertex predicate used to filter the vertices to put in the condensed graph. + /// is . + /// is . + /// is . public EdgeMergeCondensationGraphAlgorithm( [NotNull] IBidirectionalGraph visitedGraph, [NotNull] IMutableBidirectionalGraph> condensedGraph, @@ -53,7 +56,9 @@ protected override void InternalCompute() { CondensedGraph.AddVertex(vertex); if (!VertexPredicate(vertex)) + { filteredVertices.Enqueue(vertex); + } } // Adding all edges diff --git a/src/QuikGraph/Algorithms/Condensation/MergedEdge.cs b/src/QuikGraph/Algorithms/Condensation/MergedEdge.cs index 2a1a77eb8..d430b5a13 100644 --- a/src/QuikGraph/Algorithms/Condensation/MergedEdge.cs +++ b/src/QuikGraph/Algorithms/Condensation/MergedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -20,6 +20,8 @@ public sealed class MergedEdge : Edge /// /// The source vertex. /// The target vertex. + /// is . + /// is . public MergedEdge([NotNull] TVertex source, [NotNull] TVertex target) : base(source, target) { @@ -40,6 +42,8 @@ public MergedEdge([NotNull] TVertex source, [NotNull] TVertex target) /// First edge. /// Second edge. /// The merged edge. + /// is . + /// is . [Pure] [NotNull] public static MergedEdge Merge( @@ -63,7 +67,7 @@ public static MergedEdge Merge( } /// - /// Helpers for . + /// Helpers for . /// public static class MergedEdge { diff --git a/src/QuikGraph/Algorithms/ConnectedComponents/ConnectedComponentsAlgorithm.cs b/src/QuikGraph/Algorithms/ConnectedComponents/ConnectedComponentsAlgorithm.cs index 01b27e47f..a725eeadb 100644 --- a/src/QuikGraph/Algorithms/ConnectedComponents/ConnectedComponentsAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ConnectedComponents/ConnectedComponentsAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; using QuikGraph.Algorithms.Search; @@ -20,6 +20,7 @@ public sealed class ConnectedComponentsAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public ConnectedComponentsAlgorithm([NotNull] IUndirectedGraph visitedGraph) : this(visitedGraph, new Dictionary()) { @@ -30,6 +31,8 @@ public ConnectedComponentsAlgorithm([NotNull] IUndirectedGraph v /// /// Graph to visit. /// Graph components. + /// is . + /// is . public ConnectedComponentsAlgorithm( [NotNull] IUndirectedGraph visitedGraph, [NotNull] IDictionary components) @@ -43,6 +46,8 @@ public ConnectedComponentsAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Graph components. + /// is . + /// is . public ConnectedComponentsAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, diff --git a/src/QuikGraph/Algorithms/ConnectedComponents/IncrementalConnectedComponentsAlgorithm.cs b/src/QuikGraph/Algorithms/ConnectedComponents/IncrementalConnectedComponentsAlgorithm.cs index 7e0d5872a..4f953368d 100644 --- a/src/QuikGraph/Algorithms/ConnectedComponents/IncrementalConnectedComponentsAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ConnectedComponents/IncrementalConnectedComponentsAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -25,6 +25,7 @@ public sealed class IncrementalConnectedComponentsAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public IncrementalConnectedComponentsAlgorithm( [NotNull] IMutableVertexAndEdgeSet visitedGraph) : this(null, visitedGraph) @@ -36,6 +37,7 @@ public IncrementalConnectedComponentsAlgorithm( /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . public IncrementalConnectedComponentsAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableVertexAndEdgeSet visitedGraph) @@ -52,11 +54,15 @@ protected override void InternalCompute() // Initialize one set per vertex foreach (TVertex vertex in VisitedGraph.Vertices) + { _sets.MakeSet(vertex); + } // Join existing edges foreach (TEdge edge in VisitedGraph.Edges) + { _sets.Union(edge.Source, edge.Target); + } // Hook to graph event if (_hooked) @@ -75,6 +81,7 @@ protected override void InternalCompute() /// /// Number of components. /// + /// The algorithm has not been run. public int ComponentCount { get @@ -92,6 +99,7 @@ public int ComponentCount /// Value contains the vertex -> component index map. /// /// Number of components associated to components vertex mapping. + /// The algorithm has not been run. public KeyValuePair> GetComponents() { if (_sets is null) @@ -99,13 +107,18 @@ public KeyValuePair> GetComponents() var representatives = new Dictionary(_sets.SetCount); if (_components is null) + { _components = new Dictionary(VisitedGraph.VertexCount); + } + foreach (TVertex vertex in VisitedGraph.Vertices) { TVertex representative = _sets.FindSet(vertex); // ReSharper disable once AssignNullToNotNullAttribute, Justification: All graph vertices are in a set if (!representatives.TryGetValue(representative, out int index)) + { representatives[representative] = index = representatives.Count; + } _components[vertex] = index; } diff --git a/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs b/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs index fe1391248..fcfe43cee 100644 --- a/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ConnectedComponents/StronglyConnectedComponentAlgorithm.cs @@ -31,6 +31,7 @@ public sealed class StronglyConnectedComponentsAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public StronglyConnectedComponentsAlgorithm( [NotNull] IVertexListGraph visitedGraph) : this(visitedGraph, new Dictionary()) @@ -42,6 +43,8 @@ public StronglyConnectedComponentsAlgorithm( /// /// Graph to visit. /// Graph components. + /// is . + /// is . public StronglyConnectedComponentsAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] IDictionary components) @@ -55,6 +58,8 @@ public StronglyConnectedComponentsAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Graph components. + /// is . + /// is . public StronglyConnectedComponentsAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, diff --git a/src/QuikGraph/Algorithms/ConnectedComponents/WeaklyConnectedComponentsAlgorithm.cs b/src/QuikGraph/Algorithms/ConnectedComponents/WeaklyConnectedComponentsAlgorithm.cs index 7fa28ce83..baf624a3f 100644 --- a/src/QuikGraph/Algorithms/ConnectedComponents/WeaklyConnectedComponentsAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ConnectedComponents/WeaklyConnectedComponentsAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -35,6 +35,7 @@ public sealed class WeaklyConnectedComponentsAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public WeaklyConnectedComponentsAlgorithm( [NotNull] IVertexListGraph visitedGraph) : this(visitedGraph, new Dictionary()) @@ -46,6 +47,8 @@ public WeaklyConnectedComponentsAlgorithm( /// /// Graph to visit. /// Graph components. + /// is . + /// is . public WeaklyConnectedComponentsAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] IDictionary components) @@ -59,6 +62,8 @@ public WeaklyConnectedComponentsAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Graph components. + /// is . + /// is . public WeaklyConnectedComponentsAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -104,7 +109,6 @@ public BidirectionalGraph[] Graphs return _graphs; } - } #region AlgorithmBase @@ -175,7 +179,9 @@ private void MergeEquivalentComponents() int component = Components[vertex]; int equivalent = GetComponentEquivalence(component); if (component != equivalent) + { Components[vertex] = equivalent; + } } } @@ -206,7 +212,9 @@ private void ReduceComponentsIndexes() { int component = Components[vertex]; if (_componentEquivalences.TryGetValue(component, out int newComponentValue)) + { Components[vertex] = newComponentValue; + } } } @@ -273,12 +281,11 @@ private int GetComponentEquivalence(int component) // Path compression if (compress) { - int c = component; - temp = _componentEquivalences[c]; + temp = _componentEquivalences[component]; while (temp != equivalent) { - temp = _componentEquivalences[c]; - _componentEquivalences[c] = equivalent; + temp = _componentEquivalences[component]; + _componentEquivalences[component] = equivalent; } } diff --git a/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs b/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs index ebd4dbbaf..5f73ff568 100644 --- a/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs +++ b/src/QuikGraph/Algorithms/EulerianTrailAlgorithm.cs @@ -32,6 +32,7 @@ public sealed class EulerianTrailAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public EulerianTrailAlgorithm( [NotNull] IMutableVertexAndEdgeListGraph visitedGraph) : this(null, visitedGraph) @@ -43,6 +44,7 @@ public EulerianTrailAlgorithm( /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . public EulerianTrailAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableVertexAndEdgeListGraph visitedGraph) @@ -149,7 +151,7 @@ private bool Search([NotNull] TVertex vertex) _temporaryCircuit.Remove(edge); } - // It's a dead end. + // It's a dead end return false; } @@ -182,6 +184,7 @@ private bool Visit() /// /// Graph to visit. /// Number of Eulerian trails. + /// is . [Pure] public static int ComputeEulerianPathCount( [NotNull] IVertexAndEdgeListGraph graph) @@ -256,12 +259,13 @@ protected override void InternalCompute() return; if (!TryGetRootVertex(out TVertex root)) + { root = VisitedGraph.Vertices.First(); + } _currentVertex = root; // Start search - // ReSharper disable once AssignNullToNotNullAttribute, Justification: Found vertex cannot be null Search(_currentVertex); if (CircuitAugmentation()) return; // Circuit is found @@ -323,6 +327,11 @@ private bool FindAdjacentOddVertex( /// /// Edge factory method. /// Temporary edges list. + /// is . + /// + /// Number of odd vertices is not even, failed to add temporary edge to , + /// or failed to compute eulerian trail. + /// [NotNull, ItemNotNull] public TEdge[] AddTemporaryEdges([NotNull, InstantHandle] EdgeFactory edgeFactory) { @@ -393,7 +402,9 @@ public void RemoveTemporaryEdges() { // Remove from graph foreach (TEdge edge in _temporaryEdges) + { VisitedGraph.RemoveEdge(edge); + } _temporaryEdges.Clear(); } @@ -421,7 +432,9 @@ public IEnumerable> Trails() trail = new List(); } else + { trail.Add(edge); + } } if (trail.Count != 0) @@ -455,7 +468,8 @@ public IEnumerable> Trails() /// /// Starting vertex. /// Eulerian trail set, all starting at . - /// Eulerian trail not computed yet. + /// is . + /// Eulerian trail not computed yet. [NotNull, ItemNotNull] public IEnumerable> Trails([NotNull] TVertex startingVertex) { @@ -465,6 +479,7 @@ public IEnumerable> Trails([NotNull] TVertex startingVertex) return TrailsInternal(startingVertex); } + [Pure] private int FindFirstEdgeInCircuit([NotNull] TVertex startingVertex) { int i; @@ -514,7 +529,9 @@ private IEnumerable> TrailsInternal([NotNull] TVertex startin trail = new List(path); } else + { trail.Add(edge); + } } // Starting again on the circuit @@ -534,7 +551,9 @@ private IEnumerable> TrailsInternal([NotNull] TVertex startin trail = new List(path); } else + { trail.Add(edge); + } } } diff --git a/src/QuikGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs b/src/QuikGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs index d58c4c37d..743e79945 100644 --- a/src/QuikGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Exploration/CloneableVertexGraphExplorerAlgorithm.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_CLONEABLE +#if SUPPORTS_CLONEABLE using System; using System.Collections.Generic; using System.Diagnostics; @@ -23,6 +23,7 @@ public sealed class CloneableVertexGraphExplorerAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public CloneableVertexGraphExplorerAlgorithm( [NotNull] IMutableVertexAndEdgeSet visitedGraph) : this(null, visitedGraph) @@ -34,6 +35,7 @@ public CloneableVertexGraphExplorerAlgorithm( /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . public CloneableVertexGraphExplorerAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableVertexAndEdgeSet visitedGraph) @@ -54,6 +56,7 @@ public CloneableVertexGraphExplorerAlgorithm( /// /// Predicate that a vertex must match to be added in the graph. /// + /// Set value is . [NotNull] public VertexPredicate AddVertexPredicate { @@ -67,6 +70,7 @@ public VertexPredicate AddVertexPredicate /// /// Predicate that checks if a given vertex should be explored or ignored. /// + /// Set value is . [NotNull] public VertexPredicate ExploreVertexPredicate { @@ -80,6 +84,7 @@ public VertexPredicate ExploreVertexPredicate /// /// Predicate that an edge must match to be added in the graph. /// + /// Set value is . [NotNull] public EdgePredicate AddEdgePredicate { @@ -94,6 +99,7 @@ public EdgePredicate AddEdgePredicate /// /// Predicate that checks if the exploration is finished or not. /// + /// Set value is . [NotNull] public Predicate> FinishedPredicate { @@ -174,6 +180,7 @@ private void OnEdgeSkipped([NotNull] TEdge edge) /// Adds a new to this algorithm. /// /// Transition factory to add. + /// is . public void AddTransitionFactory([NotNull] ITransitionFactory transitionFactory) { if (transitionFactory is null) @@ -186,6 +193,7 @@ public void AddTransitionFactory([NotNull] ITransitionFactory tr /// Adds new s to this algorithm. /// /// Transition factories to add. + /// is . public void AddTransitionFactories( [NotNull, ItemNotNull] IEnumerable> transitionFactories) { @@ -248,7 +256,7 @@ protected override void InternalCompute() } TVertex current = _unExploredVertices.Dequeue(); - TVertex clone = (TVertex)current.Clone(); + var clone = (TVertex)current.Clone(); // Let's make sure we want to explore this one if (!ExploreVertexPredicate(clone)) @@ -341,9 +349,13 @@ public DefaultFinishedPredicate(int maxVertexCount, int maxEdgeCount) /// /// Algorithm explorer to check. /// True if the explorer can continue to explore, false otherwise. + /// is . [Pure] - public bool Test(CloneableVertexGraphExplorerAlgorithm algorithm) + public bool Test([NotNull] CloneableVertexGraphExplorerAlgorithm algorithm) { + if (algorithm is null) + throw new ArgumentNullException(nameof(algorithm)); + if (algorithm.VisitedGraph.VertexCount > MaxVertexCount) return false; diff --git a/src/QuikGraph/Algorithms/Exploration/ITransitionFactory.cs b/src/QuikGraph/Algorithms/Exploration/ITransitionFactory.cs index 71a030234..3cece82be 100644 --- a/src/QuikGraph/Algorithms/Exploration/ITransitionFactory.cs +++ b/src/QuikGraph/Algorithms/Exploration/ITransitionFactory.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_CLONEABLE +#if SUPPORTS_CLONEABLE using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -23,6 +23,7 @@ public interface ITransitionFactory /// /// Vertex to check. /// True if the vertex is valid, false otherwise. + /// is . bool IsValid([NotNull] TVertex vertex); /// @@ -30,6 +31,7 @@ public interface ITransitionFactory /// /// Source vertex. /// Edges resulting of the apply. + /// is . [NotNull, ItemNotNull] IEnumerable Apply([NotNull] TVertex source); } diff --git a/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs b/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs index 7fae07a22..651c73c08 100644 --- a/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs +++ b/src/QuikGraph/Algorithms/Exploration/TransitionFactoryImplicitGraph.cs @@ -55,6 +55,7 @@ private void MoveMainCacheToNotProcessedVertices() /// Adds a new to this graph. /// /// Transition factory to add. + /// is . public void AddTransitionFactory([NotNull] ITransitionFactory transitionFactory) { if (transitionFactory is null) @@ -68,6 +69,7 @@ public void AddTransitionFactory([NotNull] ITransitionFactory tr /// Adds new s to this graph. /// /// Transition factories to add. + /// is . public void AddTransitionFactories( [NotNull, ItemNotNull] IEnumerable> transitionFactories) { @@ -97,10 +99,12 @@ public bool RemoveTransitionFactory([CanBeNull] ITransitionFactory>> pair in _verticesNotProcessedCache.ToArray()) { if (pair.Value.Count == 0 || pair.Value.Contains(transitionFactory)) + { _verticesNotProcessedCache.Remove(pair.Key); + } } } @@ -133,6 +137,7 @@ public bool ContainsTransitionFactory([CanBeNull] ITransitionFactory /// Predicate that a vertex must match to be the successor (target) of an edge. /// + /// Set value is . [NotNull] public VertexPredicate SuccessorVertexPredicate { @@ -150,6 +155,7 @@ public VertexPredicate SuccessorVertexPredicate /// /// Predicate that an edge must match to be the successor of a source vertex. /// + /// Set value is . [NotNull] public EdgePredicate SuccessorEdgePredicate { @@ -240,7 +246,9 @@ private IEdgeList ExploreFactoriesForVertex([NotNull] TVertex ve continue; if (edges is null) + { edges = new EdgeList(); + } foreach (TEdge edge in transitionFactory.Apply(vertex).Where(edge => SuccessorVertexPredicate(edge.Target))) { @@ -264,16 +272,16 @@ public bool TryGetOutEdges(TVertex vertex, out IEnumerable edges) bool wasNotProcessed = _verticesNotProcessedCache.Remove(vertex); - if (!_verticesEdgesCache.TryGetValue(vertex, out IEdgeList e)) + if (!_verticesEdgesCache.TryGetValue(vertex, out IEdgeList edgeList)) { - e = ExploreFactoriesForVertex(vertex); + edgeList = ExploreFactoriesForVertex(vertex); - if (e is null) + if (edgeList is null) { // Vertex has no out edges if (wasNotProcessed) { - e = new EdgeList(); + edgeList = new EdgeList(); } else { @@ -282,10 +290,10 @@ public bool TryGetOutEdges(TVertex vertex, out IEnumerable edges) } } - _verticesEdgesCache[vertex] = e; + _verticesEdgesCache[vertex] = edgeList; } - edges = e.AsEnumerable(); + edges = edgeList.AsEnumerable(); return true; } diff --git a/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs b/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs index 408199dde..0cf86246f 100644 --- a/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs +++ b/src/QuikGraph/Algorithms/GraphPartition/KernighanLinAlgorithm.cs @@ -32,6 +32,7 @@ public sealed class KernighanLinAlgorithm : AlgorithmBase /// Graph to visit. /// Number of iterations to perform. + /// is . public KernighanLinAlgorithm( [NotNull] IUndirectedGraph visitedGraph, int nbIterations) @@ -134,9 +135,13 @@ private double GetVertexCost([NotNull] TVertex vertex) continue; if (vertexIsInA != vertexNeighborIsInA) // External + { cost += edge.Tag; + } else + { cost -= edge.Tag; + } } return cost; @@ -156,7 +161,9 @@ private IEnumerable GetNeighbors([NotNull] TVertex vertex) } if (neighbors.Contains(vertex)) + { neighbors.Remove(vertex); + } return neighbors; } @@ -226,9 +233,13 @@ private void GetStartPartition() foreach (TVertex vertex in VisitedGraph.Vertices) { if (i < _partitionSize) + { _vertexSetA.Add(vertex); + } else + { _vertexSetB.Add(vertex); + } ++i; } diff --git a/src/QuikGraph/Algorithms/GraphPartition/Partition.cs b/src/QuikGraph/Algorithms/GraphPartition/Partition.cs index 784813b7f..e54b02b9f 100644 --- a/src/QuikGraph/Algorithms/GraphPartition/Partition.cs +++ b/src/QuikGraph/Algorithms/GraphPartition/Partition.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SORTEDSET +#if SUPPORTS_SORTEDSET using System.Collections.Generic; #else using QuikGraph.Collections; @@ -36,6 +36,8 @@ public struct Partition /// First partition vertex set. /// Second partition vertex set. /// Cost of the partition cut. + /// is . + /// is . public Partition( [NotNull, ItemNotNull] SortedSet vertexSetA, [NotNull, ItemNotNull] SortedSet vertexSetB, @@ -52,6 +54,7 @@ public Partition( /// First partition. /// Second partition. /// True if both partitions are at least equivalent, false otherwise. + [Pure] public static bool AreEquivalent(Partition partition1, Partition partition2) { return partition1.VertexSetA.SetEquals(partition2.VertexSetA) @@ -74,6 +77,7 @@ public static class PartitionHelpers /// First partition. /// Second partition. /// True if both partitions are at least equivalent, false otherwise. + [Pure] public static bool AreEquivalent(Partition partition1, Partition partition2) { return Partition.AreEquivalent(partition1, partition2); diff --git a/src/QuikGraph/Algorithms/IsEulerianGraphAlgorithm.cs b/src/QuikGraph/Algorithms/IsEulerianGraphAlgorithm.cs index c42e7202f..8edb4a5a6 100644 --- a/src/QuikGraph/Algorithms/IsEulerianGraphAlgorithm.cs +++ b/src/QuikGraph/Algorithms/IsEulerianGraphAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -22,6 +22,7 @@ public class IsEulerianGraphAlgorithm /// Initializes a new instance of the class. /// /// Graph to check. + /// is . public IsEulerianGraphAlgorithm([NotNull] IUndirectedGraph graph) { if (graph is null) @@ -139,6 +140,7 @@ public static class IsEulerianGraphAlgorithm /// Edge type. /// Graph to check. /// True if the is Eulerian, false otherwise. + /// is . [Pure] public static bool IsEulerian( [NotNull] IUndirectedGraph graph) diff --git a/src/QuikGraph/Algorithms/IsHamiltonianGraphAlgorithm.cs b/src/QuikGraph/Algorithms/IsHamiltonianGraphAlgorithm.cs index 0c0420bed..0323a1d76 100644 --- a/src/QuikGraph/Algorithms/IsHamiltonianGraphAlgorithm.cs +++ b/src/QuikGraph/Algorithms/IsHamiltonianGraphAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Collections.Generic; using JetBrains.Annotations; @@ -23,6 +23,7 @@ public class IsHamiltonianGraphAlgorithm /// Initializes a new instance of the class. /// /// Graph to check. + /// is . public IsHamiltonianGraphAlgorithm([NotNull] IUndirectedGraph graph) { if (graph is null) @@ -143,6 +144,7 @@ public static class IsHamiltonianGraphAlgorithm /// Edge type. /// Graph to check. /// True if the is Hamiltonian, false otherwise. + /// is . [Pure] public static bool IsHamiltonian( [NotNull] IUndirectedGraph graph) diff --git a/src/QuikGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs index 9d3ea5660..efd9bf1fd 100644 --- a/src/QuikGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumBipartiteMatchingAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; using QuikGraph.Algorithms.MaximumFlow; @@ -22,6 +22,11 @@ public sealed class MaximumBipartiteMatchingAlgorithm : Algorith /// Vertices from which creating augmented edge to super sink. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// is . public MaximumBipartiteMatchingAlgorithm( [NotNull] IMutableVertexAndEdgeListGraph visitedGraph, [NotNull, ItemNotNull] IEnumerable sourceToVertices, diff --git a/src/QuikGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs index 7da30aaa1..6ffcf20b1 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/AllVerticesGraphAugmentorAlgorithm.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; using QuikGraph.Algorithms.Services; namespace QuikGraph.Algorithms.MaximumFlow @@ -19,6 +19,9 @@ public sealed class AllVerticesGraphAugmentorAlgorithm /// Graph to visit. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . public AllVerticesGraphAugmentorAlgorithm( [NotNull] IMutableVertexAndEdgeSet visitedGraph, [NotNull] VertexFactory vertexFactory, @@ -34,6 +37,9 @@ public AllVerticesGraphAugmentorAlgorithm( /// Graph to visit. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . public AllVerticesGraphAugmentorAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableVertexAndEdgeSet visitedGraph, diff --git a/src/QuikGraph/Algorithms/MaximumFlow/BipartiteToMaximumFlowGraphAugmentorAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/BipartiteToMaximumFlowGraphAugmentorAlgorithm.cs index 150168444..88d109be2 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/BipartiteToMaximumFlowGraphAugmentorAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/BipartiteToMaximumFlowGraphAugmentorAlgorithm.cs @@ -26,6 +26,11 @@ internal sealed class BipartiteToMaximumFlowGraphAugmentorAlgorithmVertices from which creating augmented edge to super sink. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// is . public BipartiteToMaximumFlowGraphAugmentorAlgorithm( [NotNull] IMutableVertexAndEdgeSet visitedGraph, [NotNull, ItemNotNull] IEnumerable sourceToVertices, @@ -45,6 +50,11 @@ public BipartiteToMaximumFlowGraphAugmentorAlgorithm( /// Vertices from which creating augmented edge to super sink. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// is . public BipartiteToMaximumFlowGraphAugmentorAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableVertexAndEdgeSet visitedGraph, diff --git a/src/QuikGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs index 288e1c1dd..07af24118 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/EdmondsKarpMaximumFlowAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -27,6 +27,11 @@ public sealed class EdmondsKarpMaximumFlowAlgorithm : MaximumFlo /// Function that given an edge return the capacity of this edge. /// Edge factory method. /// Algorithm that is in of charge of augmenting the graph (creating missing reversed edges). + /// is . + /// is . + /// is . + /// is . + /// targets a graph different from . public EdmondsKarpMaximumFlowAlgorithm( [NotNull] IMutableVertexAndEdgeListGraph visitedGraph, [NotNull] Func capacities, @@ -44,6 +49,11 @@ public EdmondsKarpMaximumFlowAlgorithm( /// Function that given an edge return the capacity of this edge. /// Edge factory method. /// Algorithm that is in of charge augmenting the graph (creating missing reversed edges). + /// is . + /// is . + /// is . + /// is . + /// targets a graph different from . public EdmondsKarpMaximumFlowAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableVertexAndEdgeListGraph visitedGraph, @@ -156,12 +166,16 @@ protected override void InternalCompute() bfs.Compute(Source); if (VerticesColors[Sink] != GraphColor.White) + { Augment(Source, Sink); + } } MaxFlow = 0; foreach (TEdge edge in graph.OutEdges(Source)) - MaxFlow += (Capacities(edge) - ResidualCapacities[edge]); + { + MaxFlow += Capacities(edge) - ResidualCapacities[edge]; + } } #endregion diff --git a/src/QuikGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs b/src/QuikGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs index 0c69b3ba0..1454c1a57 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/GraphAugmentorAlgorithmBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -23,6 +23,9 @@ public abstract class GraphAugmentorAlgorithmBase : Algo /// Graph to visit. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . protected GraphAugmentorAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] TGraph visitedGraph, diff --git a/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs index a7f5b0871..b60d0c345 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -26,6 +26,13 @@ public sealed class GraphBalancerAlgorithm /// Flow sink vertex. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . + /// is . + /// is . + /// does not contain vertex. + /// does not contain vertex. public GraphBalancerAlgorithm( [NotNull] IMutableBidirectionalGraph visitedGraph, [NotNull] TVertex source, @@ -68,6 +75,14 @@ public GraphBalancerAlgorithm( /// Vertex factory method. /// Edge factory method. /// Edges capacities. + /// is . + /// is . + /// is . + /// is . + /// is . + /// is . + /// does not contain vertex. + /// does not contain vertex. public GraphBalancerAlgorithm( [NotNull] IMutableBidirectionalGraph visitedGraph, [NotNull] TVertex source, @@ -95,7 +110,9 @@ public GraphBalancerAlgorithm( // Setting preflow = l(e) = 1 foreach (TEdge edge in VisitedGraph.Edges) + { _preFlow.Add(edge, 1); + } } /// @@ -266,12 +283,7 @@ public int GetBalancingIndex([NotNull] TVertex vertex) if (vertex == null) throw new ArgumentNullException(nameof(vertex)); - int balancingIndex = 0; - foreach (TEdge edge in VisitedGraph.OutEdges(vertex)) - { - int preFlow = _preFlow[edge]; - balancingIndex += preFlow; - } + int balancingIndex = VisitedGraph.OutEdges(vertex).Sum(edge => _preFlow[edge]); foreach (TEdge edge in VisitedGraph.InEdges(vertex)) { @@ -285,7 +297,7 @@ public int GetBalancingIndex([NotNull] TVertex vertex) /// /// Runs the graph balancing algorithm. /// - /// If the graph is already balanced. + /// If the graph is already balanced. public void Balance() { if (Balanced) @@ -375,7 +387,7 @@ bool IsSourceOrSink(TVertex v) /// /// Runs the graph unbalancing algorithm. /// - /// If the graph is not balanced. + /// If the graph is not balanced. public void UnBalance() { if (!Balanced) diff --git a/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs b/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs index 9e2b688a5..c123fbf70 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; using QuikGraph.Algorithms.Services; @@ -22,6 +22,9 @@ public abstract class MaximumFlowAlgorithm /// Graph to visit. /// Function that given an edge return the capacity of this edge. /// Edge factory method. + /// is . + /// is . + /// is . protected MaximumFlowAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableVertexAndEdgeListGraph visitedGraph, @@ -103,11 +106,16 @@ public GraphColor GetVertexColor(TVertex vertex) #endregion /// - /// Compute the maximum flow value. + /// Computes the maximum flow value. /// /// Flow source vertex. /// Flow sink vertex. /// Maximum flow value. + /// is . + /// is . + /// Something went wrong when running the algorithm. + /// is not part of . + /// is not part of . public double Compute([NotNull] TVertex source, [NotNull] TVertex sink) { if (source == null) @@ -123,5 +131,4 @@ public double Compute([NotNull] TVertex source, [NotNull] TVertex sink) return MaxFlow; } } - } \ No newline at end of file diff --git a/src/QuikGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs index be5d89f24..1dea09bf3 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/MultiSourceSinkGraphAugmentorAlgorithm.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; using QuikGraph.Algorithms.Services; namespace QuikGraph.Algorithms.MaximumFlow @@ -18,6 +18,9 @@ public sealed class MultiSourceSinkGraphAugmentorAlgorithm /// Graph to visit. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . public MultiSourceSinkGraphAugmentorAlgorithm( [NotNull] IMutableBidirectionalGraph visitedGraph, [NotNull] VertexFactory vertexFactory, @@ -33,6 +36,9 @@ public MultiSourceSinkGraphAugmentorAlgorithm( /// Graph to visit. /// Vertex factory method. /// Edge factory method. + /// is . + /// is . + /// is . public MultiSourceSinkGraphAugmentorAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IMutableBidirectionalGraph visitedGraph, @@ -51,11 +57,15 @@ protected override void AugmentGraph() // Is source if (VisitedGraph.IsInEdgesEmpty(vertex)) + { AddAugmentedEdge(SuperSource, vertex); + } // Is sink if (VisitedGraph.IsOutEdgesEmpty(vertex)) + { AddAugmentedEdge(vertex, SuperSink); + } } } } diff --git a/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs index 15feeeebf..665d34e13 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/ReverseEdgeAugmentorAlgorithm.cs @@ -21,6 +21,8 @@ public sealed class ReversedEdgeAugmentorAlgorithm : IDisposable /// /// Graph to visit. /// Edge factory method. + /// is . + /// is . public ReversedEdgeAugmentorAlgorithm( [NotNull] IMutableVertexAndEdgeListGraph visitedGraph, [NotNull] EdgeFactory edgeFactory) @@ -114,7 +116,9 @@ private IEnumerable FindEdgesToReverse() // Setup reversed if needed if (!ReversedEdges.ContainsKey(reversedEdge)) + { ReversedEdges[reversedEdge] = edge; + } continue; } @@ -154,7 +158,7 @@ private void AddReversedEdges([NotNull, ItemNotNull] IEnumerable notRever /// /// Adds auxiliary edges to to store residual flows. /// - /// If the graph is already augmented. + /// If the graph is already augmented. public void AddReversedEdges() { if (Augmented) @@ -172,14 +176,16 @@ public void AddReversedEdges() /// /// Removes reversed edges that were added. /// - /// If the graph was not augmented yet. + /// If the graph was not augmented yet. public void RemoveReversedEdges() { if (!Augmented) throw new InvalidOperationException("Graph is not augmented yet."); foreach (TEdge edge in _augmentedEdges) + { VisitedGraph.RemoveEdge(edge); + } _augmentedEdges.Clear(); ReversedEdges.Clear(); @@ -193,7 +199,9 @@ public void RemoveReversedEdges() void IDisposable.Dispose() { if (Augmented) + { RemoveReversedEdges(); + } } #endregion diff --git a/src/QuikGraph/Algorithms/MinimumSpanningTree/KruskalMinimumSpanningTreeAlgorithm.cs b/src/QuikGraph/Algorithms/MinimumSpanningTree/KruskalMinimumSpanningTreeAlgorithm.cs index 2c819b9ab..7708e36c5 100644 --- a/src/QuikGraph/Algorithms/MinimumSpanningTree/KruskalMinimumSpanningTreeAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MinimumSpanningTree/KruskalMinimumSpanningTreeAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using JetBrains.Annotations; using QuikGraph.Algorithms.Services; @@ -24,6 +24,8 @@ public sealed class KruskalMinimumSpanningTreeAlgorithm /// /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public KruskalMinimumSpanningTreeAlgorithm( [NotNull] IUndirectedGraph visitedGraph, [NotNull] Func edgeWeights) @@ -37,6 +39,8 @@ public KruskalMinimumSpanningTreeAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public KruskalMinimumSpanningTreeAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, @@ -79,13 +83,17 @@ protected override void InternalCompute() { var sets = new ForestDisjointSet(VisitedGraph.VertexCount); foreach (TVertex vertex in VisitedGraph.Vertices) + { sets.MakeSet(vertex); + } ThrowIfCancellationRequested(); var queue = new BinaryQueue(_edgeWeights); foreach (TEdge edge in VisitedGraph.Edges) + { queue.Enqueue(edge); + } ThrowIfCancellationRequested(); diff --git a/src/QuikGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs b/src/QuikGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs index 537295563..978109af3 100644 --- a/src/QuikGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MinimumSpanningTree/PrimMinimumSpanningTreeAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -26,6 +26,8 @@ public sealed class PrimMinimumSpanningTreeAlgorithm /// /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public PrimMinimumSpanningTreeAlgorithm( [NotNull] IUndirectedGraph visitedGraph, [NotNull] Func edgeWeights) @@ -39,6 +41,8 @@ public PrimMinimumSpanningTreeAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public PrimMinimumSpanningTreeAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, diff --git a/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs index ee88dd25e..1c6975f2e 100644 --- a/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/EdgePredecessorRecorderObserver.cs @@ -30,6 +30,7 @@ public EdgePredecessorRecorderObserver() /// Initializes a new instance of the class. /// /// Edges predecessors. + /// is . public EdgePredecessorRecorderObserver( [NotNull] IDictionary edgesPredecessors) { @@ -74,6 +75,7 @@ public IDisposable Attach(IEdgePredecessorRecorderAlgorithm algo /// /// Starting edge. /// Edge path. + /// is . [Pure] [NotNull, ItemNotNull] public ICollection Path([NotNull] TEdge startingEdge) @@ -111,6 +113,8 @@ public IEnumerable> AllPaths() /// Starting edge. /// Edges colors mapping. /// Merged path. + /// is . + /// is . [Pure] [NotNull, ItemNotNull] public ICollection MergedPath( @@ -175,7 +179,9 @@ private void OnEdgeDiscovered([NotNull] TEdge edge, [NotNull] TEdge targetEdge) Debug.Assert(targetEdge != null); if (!EqualityComparer.Default.Equals(edge, targetEdge)) + { EdgesPredecessors[targetEdge] = edge; + } } private void OnEdgeFinished([NotNull] TEdge finishedEdge) diff --git a/src/QuikGraph/Algorithms/Observers/EdgeRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/EdgeRecorderObserver.cs index 743ccf357..47e004a52 100644 --- a/src/QuikGraph/Algorithms/Observers/EdgeRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/EdgeRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -30,6 +30,7 @@ public EdgeRecorderObserver() /// Initializes a new instance of the class. /// /// Set of edges. + /// is . public EdgeRecorderObserver([NotNull, ItemNotNull] IEnumerable edges) { if (edges is null) diff --git a/src/QuikGraph/Algorithms/Observers/UndirectedVertexDistanceRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/UndirectedVertexDistanceRecorderObserver.cs index 812fe2822..47421bec8 100644 --- a/src/QuikGraph/Algorithms/Observers/UndirectedVertexDistanceRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/UndirectedVertexDistanceRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -19,6 +19,7 @@ public sealed class UndirectedVertexDistanceRecorderObserver /// Initializes a new instance of the class. /// /// Function that computes the weight for a given edge. + /// is . public UndirectedVertexDistanceRecorderObserver([NotNull] Func edgeWeights) : this(edgeWeights, DistanceRelaxers.EdgeShortestDistance, new Dictionary()) { @@ -30,6 +31,9 @@ public UndirectedVertexDistanceRecorderObserver([NotNull] Func ed /// Function that computes the weight for a given edge. /// Distance relaxer. /// Distances per vertex. + /// is . + /// is . + /// is . public UndirectedVertexDistanceRecorderObserver( [NotNull] Func edgeWeights, [NotNull] IDistanceRelaxer distanceRelaxer, diff --git a/src/QuikGraph/Algorithms/Observers/UndirectedVertexPredecessorRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/UndirectedVertexPredecessorRecorderObserver.cs index ad3600a32..39c612589 100644 --- a/src/QuikGraph/Algorithms/Observers/UndirectedVertexPredecessorRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/UndirectedVertexPredecessorRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -30,6 +30,7 @@ public UndirectedVertexPredecessorRecorderObserver() /// Initializes a new instance of the class. /// /// Vertices predecessors. + /// is . public UndirectedVertexPredecessorRecorderObserver( [NotNull] IDictionary verticesPredecessors) { @@ -70,8 +71,10 @@ private void OnEdgeDiscovered([NotNull] object sender, [NotNull] UndirectedEdgeE /// Path ending vertex. /// Path to the ending vertex. /// True if a path was found, false otherwise. + /// is . [Pure] - public bool TryGetPath(TVertex vertex, out IEnumerable path) + [ContractAnnotation("=> true, path:notnull;=> false, path:null")] + public bool TryGetPath([NotNull] TVertex vertex, [ItemNotNull] out IEnumerable path) { return VerticesPredecessors.TryGetPath(vertex, out path); } diff --git a/src/QuikGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs index 85108bb1b..44c0cf683 100644 --- a/src/QuikGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/VertexDistanceRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -18,6 +18,7 @@ public sealed class VertexDistanceRecorderObserver : IObserver class. /// /// Function that computes the weight for a given edge. + /// is . public VertexDistanceRecorderObserver([NotNull] Func edgeWeights) : this(edgeWeights, DistanceRelaxers.EdgeShortestDistance, new Dictionary()) { @@ -29,6 +30,9 @@ public VertexDistanceRecorderObserver([NotNull] Func edgeWeights) /// Function that computes the weight for a given edge. /// Distance relaxer. /// Distances per vertex. + /// is . + /// is . + /// is . public VertexDistanceRecorderObserver( [NotNull] Func edgeWeights, [NotNull] IDistanceRelaxer distanceRelaxer, @@ -76,7 +80,9 @@ private void OnEdgeDiscovered([NotNull] TEdge edge) Debug.Assert(edge != null); if (!Distances.TryGetValue(edge.Source, out double sourceDistance)) + { Distances[edge.Source] = sourceDistance = DistanceRelaxer.InitialDistance; + } Distances[edge.Target] = DistanceRelaxer.Combine(sourceDistance, EdgeWeights(edge)); } } diff --git a/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs index 5d8742bb6..bc0a65361 100644 --- a/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/VertexPredecessorPathRecorderObserver.cs @@ -31,6 +31,7 @@ public VertexPredecessorPathRecorderObserver() /// Initializes a new instance of the class. /// /// Vertices predecessors. + /// is . public VertexPredecessorPathRecorderObserver( [NotNull] IDictionary verticesPredecessors) { @@ -58,12 +59,7 @@ public VertexPredecessorPathRecorderObserver( public IEnumerable> AllPaths() { return EndPathVertices - .Select(vertex => - { - if (VerticesPredecessors.TryGetPath(vertex, out IEnumerable path)) - return path; - return null; - }) + .Select(vertex => VerticesPredecessors.TryGetPath(vertex, out IEnumerable path) ? path : null) .Where(path => path != null); } diff --git a/src/QuikGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs index fbb84d2df..ec276f012 100644 --- a/src/QuikGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/VertexPredecessorRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -29,6 +29,7 @@ public VertexPredecessorRecorderObserver() /// Initializes a new instance of the class. /// /// Vertices predecessors. + /// is . public VertexPredecessorRecorderObserver( [NotNull] IDictionary verticesPredecessors) { @@ -68,8 +69,10 @@ private void OnEdgeDiscovered([NotNull] TEdge edge) /// Path ending vertex. /// Path to the ending vertex. /// True if a path was found, false otherwise. + /// is . [Pure] - public bool TryGetPath([NotNull] TVertex vertex, out IEnumerable path) + [ContractAnnotation("=> true, path:notnull;=> false, path:null")] + public bool TryGetPath([NotNull] TVertex vertex, [ItemNotNull] out IEnumerable path) { return VerticesPredecessors.TryGetPath(vertex, out path); } diff --git a/src/QuikGraph/Algorithms/Observers/VertexRecorderObserver.cs b/src/QuikGraph/Algorithms/Observers/VertexRecorderObserver.cs index 626b053cd..7b696b023 100644 --- a/src/QuikGraph/Algorithms/Observers/VertexRecorderObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/VertexRecorderObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -28,6 +28,7 @@ public VertexRecorderObserver() /// Initializes a new instance of the class. /// /// Set of vertices. + /// is . public VertexRecorderObserver([NotNull, ItemNotNull] IEnumerable vertices) { if (vertices is null) diff --git a/src/QuikGraph/Algorithms/Observers/VertexTimeStamperObserver.cs b/src/QuikGraph/Algorithms/Observers/VertexTimeStamperObserver.cs index 1921615e9..81238acf9 100644 --- a/src/QuikGraph/Algorithms/Observers/VertexTimeStamperObserver.cs +++ b/src/QuikGraph/Algorithms/Observers/VertexTimeStamperObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -29,6 +29,7 @@ public VertexTimeStamperObserver() /// Initializes a new instance of the class. /// /// Vertices discover times. + /// is . public VertexTimeStamperObserver([NotNull] IDictionary discoverTimes) { DiscoverTimes = discoverTimes ?? throw new ArgumentNullException(nameof(discoverTimes)); @@ -40,6 +41,8 @@ public VertexTimeStamperObserver([NotNull] IDictionary discoverTim /// /// Vertices discover times. /// Vertices fully treated times. + /// is . + /// is . public VertexTimeStamperObserver( [NotNull] IDictionary discoverTimes, [NotNull] IDictionary finishTimes) @@ -70,13 +73,17 @@ public IDisposable Attach(IVertexTimeStamperAlgorithm algorithm) algorithm.DiscoverVertex += OnVertexDiscovered; if (FinishTimes != null) + { algorithm.FinishVertex += OnVertexFinished; + } return Finally(() => { algorithm.DiscoverVertex -= OnVertexDiscovered; if (FinishTimes != null) + { algorithm.FinishVertex -= OnVertexFinished; + } }); } diff --git a/src/QuikGraph/Algorithms/PageRankAlgorithm.cs b/src/QuikGraph/Algorithms/PageRankAlgorithm.cs index b269e6456..9aa02694d 100644 --- a/src/QuikGraph/Algorithms/PageRankAlgorithm.cs +++ b/src/QuikGraph/Algorithms/PageRankAlgorithm.cs @@ -18,6 +18,7 @@ public sealed class PageRankAlgorithm : AlgorithmBase class. /// /// Graph to visit. + /// is . public PageRankAlgorithm([NotNull] IBidirectionalGraph visitedGraph) : base(visitedGraph) { @@ -35,6 +36,7 @@ public PageRankAlgorithm([NotNull] IBidirectionalGraph visitedGr /// Gets or sets the damping rate [0-1]. /// /// By default it uses 0.85 which is the value generally used. + /// Value is negative or higher than 1. public double Damping { get => _damping; @@ -51,6 +53,7 @@ public double Damping /// /// Gets or sets the error tolerance (used to stop the algorithm). /// + /// Value is negative. public double Tolerance { get => _tolerance; @@ -67,6 +70,7 @@ public double Tolerance /// /// Gets or sets the maximum number of iterations. /// + /// Value is negative or equal 0. public int MaxIterations { get => _maxIterations; diff --git a/src/QuikGraph/Algorithms/RandomGraphFactory.cs b/src/QuikGraph/Algorithms/RandomGraphFactory.cs index 903adc01b..31d693122 100644 --- a/src/QuikGraph/Algorithms/RandomGraphFactory.cs +++ b/src/QuikGraph/Algorithms/RandomGraphFactory.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -16,6 +16,8 @@ public static class RandomGraphFactory /// The graph. /// Random number generator. /// Chosen vertex. + /// is . + /// is . [Pure] [NotNull] public static TVertex GetVertex( @@ -35,6 +37,10 @@ public static TVertex GetVertex( /// Number of vertices in the set. /// Random number generator. /// Chosen vertex. + /// is . + /// is . + /// is negative or equal 0. + /// is higher than count. [Pure] [NotNull] public static TVertex GetVertex( @@ -69,6 +75,8 @@ public static TVertex GetVertex( /// The graph. /// Random number generator. /// Chosen vertex. + /// is . + /// is . [Pure] [NotNull] public static TEdge GetEdge( @@ -90,6 +98,10 @@ public static TEdge GetEdge( /// Number of edges in the set. /// Random number generator. /// Chosen vertex. + /// is . + /// is . + /// is negative or equal 0. + /// is higher than count. [Pure] [NotNull] public static TEdge GetEdge( @@ -136,8 +148,8 @@ private static void CreateInternal( if (rng is null) throw new ArgumentNullException(nameof(rng)); if (vertexCount <= 0) - throw new ArgumentOutOfRangeException(nameof(vertexCount), "Must have at least one vertex."); - if (edgeCount <= 0) + throw new ArgumentOutOfRangeException(nameof(vertexCount), "Must request at least one vertex."); + if (edgeCount < 0) throw new ArgumentOutOfRangeException(nameof(edgeCount), "Must not be negative."); var vertices = new TVertex[vertexCount]; @@ -160,7 +172,9 @@ private static void CreateInternal( while (!selfEdges && EqualityComparer.Default.Equals(a, b)); if (graph.AddEdge(edgeFactory(a, b))) + { ++j; + } } } @@ -177,6 +191,12 @@ private static void CreateInternal( /// Number of vertices to create. /// Number of edges to create. /// Indicates if self edge are allowed. + /// is . + /// is . + /// is . + /// is . + /// is negative or equal 0. + /// is negative. public static void Create( [NotNull] IMutableVertexAndEdgeListGraph graph, [NotNull, InstantHandle] VertexFactory vertexFactory, @@ -203,6 +223,12 @@ public static void Create( /// Number of vertices to create. /// Number of edges to create. /// Indicates if self edge are allowed. + /// is . + /// is . + /// is . + /// is . + /// is negative or equal 0. + /// is negative. public static void Create( [NotNull] IMutableUndirectedGraph graph, [NotNull, InstantHandle] VertexFactory vertexFactory, diff --git a/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs b/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs index b1bd2231f..8e9a5eecf 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -25,6 +25,7 @@ public sealed class CyclePoppingRandomTreeAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public CyclePoppingRandomTreeAlgorithm([NotNull] IVertexListGraph visitedGraph) : this(visitedGraph, new NormalizedMarkovEdgeChain()) { @@ -35,6 +36,8 @@ public CyclePoppingRandomTreeAlgorithm([NotNull] IVertexListGraph /// Graph to visit. /// Edge chain strategy to use. + /// is . + /// is . public CyclePoppingRandomTreeAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] IMarkovEdgeChain edgeChain) @@ -48,6 +51,8 @@ public CyclePoppingRandomTreeAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Edge chain strategy to use. + /// is . + /// is . public CyclePoppingRandomTreeAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -92,6 +97,7 @@ public GraphColor GetVertexColor(TVertex vertex) /// /// Gets or sets the random number generator used in . /// + /// Set value is . [NotNull] public Random Rand { @@ -276,6 +282,8 @@ private void ClearTree([NotNull] TVertex vertex) /// Runs a random tree generation starting at vertex. /// /// Tree starting vertex. + /// is . + /// is part of . public void RandomTreeWithRoot([NotNull] TVertex root) { if (!VisitedGraph.ContainsVertex(root)) @@ -301,6 +309,7 @@ public void RandomTree() } while (!success); } + [Pure] private bool Attempt(double epsilon) { Initialize(); @@ -321,8 +330,11 @@ private bool Attempt(double epsilon) return true; } + [Pure] private bool Explore(double eps, [NotNull] TVertex vertex, ref int numRoots) { + Debug.Assert(vertex != null); + var visited = new Dictionary(); TVertex current = vertex; while (NotInTree(current)) @@ -352,6 +364,8 @@ private bool Explore(double eps, [NotNull] TVertex vertex, ref int numRoots) private void Colorize([NotNull] TVertex vertex) { + Debug.Assert(vertex != null); + TVertex current = vertex; while (NotInTree(current)) { diff --git a/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs b/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs index 62029e958..2185c03dd 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph.Algorithms.RandomWalks @@ -18,7 +18,10 @@ public interface IEdgeChain /// The vertex. /// Found successor, otherwise null. /// True if a successor was found, false otherwise. + /// is . + /// is . [Pure] + [ContractAnnotation("=> true, successor:notnull;=> false, successor:null")] bool TryGetSuccessor([NotNull] IImplicitGraph graph, [NotNull] TVertex vertex, out TEdge successor); /// @@ -28,7 +31,10 @@ public interface IEdgeChain /// The vertex. /// Found successor, otherwise null. /// True if a successor was found, false otherwise. + /// is . + /// is . [Pure] + [ContractAnnotation("=> true, successor:notnull;=> false, successor:null")] bool TryGetSuccessor([NotNull, ItemNotNull] IEnumerable edges, [NotNull] TVertex vertex, out TEdge successor); } } \ No newline at end of file diff --git a/src/QuikGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs b/src/QuikGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs index a73ce8769..c4fc95818 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/RandomWalkAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using JetBrains.Annotations; @@ -18,6 +18,7 @@ public sealed class RandomWalkAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public RandomWalkAlgorithm([NotNull] IImplicitGraph visitedGraph) : this(visitedGraph, new NormalizedMarkovEdgeChain()) { @@ -28,6 +29,8 @@ public RandomWalkAlgorithm([NotNull] IImplicitGraph visitedGraph /// /// Graph to visit. /// Edge chain strategy to use. + /// is . + /// is . public RandomWalkAlgorithm( [NotNull] IImplicitGraph visitedGraph, [NotNull] IEdgeChain edgeChain) @@ -107,6 +110,7 @@ protected override void InternalCompute() /// Generates a random walk with 100 steps. /// /// Root vertex. + /// is not part of . public void Generate([NotNull] TVertex root) { Generate(root, 100); @@ -116,7 +120,8 @@ public void Generate([NotNull] TVertex root) /// Generates a random walk with steps. /// /// Root vertex. - /// Number of steps for the random walk. + /// Number of steps for the random walk.VertexNotFoundException + /// is not part of . public void Generate([NotNull] TVertex root, int walkCount) { AssertRootInGraph(root); diff --git a/src/QuikGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs b/src/QuikGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs index 8caf92c39..e5fc24445 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/VanishingWeightedMarkovEdgeChain.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -16,6 +16,7 @@ public sealed class VanishingWeightedMarkovEdgeChain : WeightedM /// Initializes a new instance of the class. /// /// Map that contains edge weights. + /// is . public VanishingWeightedMarkovEdgeChain([NotNull] IDictionary edgeWeights) : this(edgeWeights, 0.2) { @@ -26,6 +27,7 @@ public VanishingWeightedMarkovEdgeChain([NotNull] IDictionary edg /// /// Map that contains edge weights. /// Vanishing factor. + /// is . public VanishingWeightedMarkovEdgeChain([NotNull] IDictionary edgeWeights, double factor) : base(edgeWeights) { diff --git a/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs b/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs index f8331293e..f55350b1b 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkedEdgeChain.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -16,6 +16,7 @@ public sealed class WeightedMarkovEdgeChain : WeightedMarkovEdge /// Initializes a new instance of the class. /// /// Map that contains edge weights. + /// is . public WeightedMarkovEdgeChain([NotNull] IDictionary edgeWeights) : base(edgeWeights) { diff --git a/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs b/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs index bc8db71ae..389ad984a 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -18,6 +18,7 @@ public abstract class WeightedMarkovEdgeChainBase : MarkovEdgeCh /// Initializes a new instance of the class. /// /// Map that contains edge weights. + /// is . protected WeightedMarkovEdgeChainBase([NotNull] IDictionary edgeWeights) { Weights = edgeWeights ?? throw new ArgumentNullException(nameof(edgeWeights)); diff --git a/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs index cb5c47cf1..bd1730d27 100644 --- a/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -35,6 +35,8 @@ public sealed class HoffmanPavleyRankedShortestPathAlgorithm /// /// Graph to visit. /// Function that for a given edge provide its weight. + /// is . + /// is . public HoffmanPavleyRankedShortestPathAlgorithm( [NotNull] IBidirectionalGraph visitedGraph, [NotNull] Func edgeWeights) @@ -48,6 +50,9 @@ public HoffmanPavleyRankedShortestPathAlgorithm( /// Graph to visit. /// Function that for a given edge provide its weight. /// Distance relaxer. + /// is . + /// is . + /// is . public HoffmanPavleyRankedShortestPathAlgorithm( [NotNull] IBidirectionalGraph visitedGraph, [NotNull] Func edgeWeights, @@ -63,6 +68,9 @@ public HoffmanPavleyRankedShortestPathAlgorithm( /// Graph to visit. /// Function that for a given edge provide its weight. /// Distance relaxer. + /// is . + /// is . + /// is . public HoffmanPavleyRankedShortestPathAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IBidirectionalGraph visitedGraph, @@ -77,6 +85,7 @@ public HoffmanPavleyRankedShortestPathAlgorithm( /// Sets the target vertex. /// /// Target vertex. + /// is . public void SetTargetVertex([NotNull] TVertex target) { if (target == null) @@ -92,6 +101,7 @@ public void SetTargetVertex([NotNull] TVertex target) /// Target vertex if set, otherwise null. /// True if the target vertex was set, false otherwise. [Pure] + [ContractAnnotation("=> true, target:notnull;=> false, target:null")] public bool TryGetTargetVertex(out TVertex target) { if (_hasTargetVertex) @@ -109,6 +119,11 @@ public bool TryGetTargetVertex(out TVertex target) /// /// Root vertex. /// Target vertex. + /// is . + /// is . + /// is not part of . + /// is not part of . + /// Something went wrong when running the algorithm. public void Compute([NotNull] TVertex root, [NotNull] TVertex target) { if (root == null) @@ -238,7 +253,9 @@ private void ComputeMinimumTree( successors = new Dictionary(); foreach (KeyValuePair> pair in successorsObserver.VerticesPredecessors) + { successors.Add(pair.Key, pair.Value.OriginalEdge); + } distances = distancesObserver.Distances; @@ -289,7 +306,9 @@ private void EnqueueDeviationPaths( // Detection of loops if (edgeIndex == 0) + { pathVertices[edge.Source] = 0; + } // We should really allow only one key if (pathVertices.ContainsKey(edge.Target)) diff --git a/src/QuikGraph/Algorithms/RankedShortestPath/RankedShortestPathAlgorithmBase.cs b/src/QuikGraph/Algorithms/RankedShortestPath/RankedShortestPathAlgorithmBase.cs index 7184acd7f..63a5e33a5 100644 --- a/src/QuikGraph/Algorithms/RankedShortestPath/RankedShortestPathAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/RankedShortestPath/RankedShortestPathAlgorithmBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -23,6 +23,8 @@ public abstract class RankedShortestPathAlgorithmBase : /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Distance relaxer. + /// is . + /// is . protected RankedShortestPathAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] TGraph visitedGraph, @@ -37,6 +39,7 @@ protected RankedShortestPathAlgorithmBase( /// /// Gets or sets the maximum number of shortest path to find. /// + /// Value is lower or equal to 1. public int ShortestPathCount { get => _shortestPathCount; diff --git a/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs b/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs index 80152f679..430692034 100644 --- a/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; #if SUPPORTS_AGGRESSIVE_INLINING @@ -31,6 +31,7 @@ public abstract class RootedAlgorithmBase : AlgorithmBase /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . protected RootedAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] TGraph visitedGraph) @@ -44,6 +45,7 @@ protected RootedAlgorithmBase( /// Root vertex if set, otherwise null. /// True if the root vertex was set, false otherwise. [Pure] + [ContractAnnotation("=> true, root:notnull;=> false, root:null")] public bool TryGetRootVertex(out TVertex root) { if (_hasRootVertex) @@ -60,6 +62,7 @@ public bool TryGetRootVertex(out TVertex root) /// Sets the root vertex. /// /// Root vertex. + /// is . public void SetRootVertex([NotNull] TVertex root) { if (root == null) @@ -70,7 +73,9 @@ public void SetRootVertex([NotNull] TVertex root) _hasRootVertex = true; if (changed) + { OnRootVertexChanged(EventArgs.Empty); + } } /// @@ -83,7 +88,9 @@ public void ClearRootVertex() _hasRootVertex = false; if (hasRoot) + { OnRootVertexChanged(EventArgs.Empty); + } } /// @@ -94,7 +101,7 @@ public void ClearRootVertex() /// /// Called on each root vertex change. /// - /// . + /// . protected virtual void OnRootVertexChanged([NotNull] EventArgs args) { Debug.Assert(args != null); @@ -107,7 +114,7 @@ protected virtual void OnRootVertexChanged([NotNull] EventArgs args) /// . /// /// Root vertex. - /// If the root vertex has not been set. + /// If the root vertex has not been set. /// /// If the set root vertex is not part of the . /// @@ -140,6 +147,9 @@ protected void AssertRootInGraph([NotNull] TVertex root) /// Runs the algorithm with the given vertex. /// /// Root vertex. + /// is . + /// is not part of . + /// Something went wrong when running the algorithm. public virtual void Compute([NotNull] TVertex root) { SetRootVertex(root); diff --git a/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs b/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs index c43b59d04..0afc1d602 100644 --- a/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -28,6 +28,7 @@ public abstract class RootedSearchAlgorithmBase : RootedAlgorit /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . protected RootedSearchAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] TGraph visitedGraph) @@ -41,6 +42,7 @@ protected RootedSearchAlgorithmBase( /// Target vertex if set, otherwise null. /// True if the target vertex was set, false otherwise. [Pure] + [ContractAnnotation("=> true, target:notnull;=> false, target:null")] public bool TryGetTargetVertex(out TVertex target) { if (_hasTargetVertex) @@ -57,6 +59,7 @@ public bool TryGetTargetVertex(out TVertex target) /// Sets the target vertex. /// /// Target vertex. + /// is . public void SetTargetVertex([NotNull] TVertex target) { if (target == null) @@ -67,7 +70,9 @@ public void SetTargetVertex([NotNull] TVertex target) _hasTargetVertex = true; if (changed) + { OnTargetVertexChanged(EventArgs.Empty); + } } /// @@ -81,7 +86,9 @@ public void ClearTargetVertex() _hasTargetVertex = false; if (hasTarget) + { OnTargetVertexChanged(EventArgs.Empty); + } } /// @@ -92,7 +99,7 @@ public void ClearTargetVertex() /// /// Called on each target vertex change. /// - /// . + /// . protected virtual void OnTargetVertexChanged([NotNull] EventArgs args) { Debug.Assert(args != null); @@ -118,6 +125,11 @@ protected virtual void OnTargetReached() /// /// Root vertex. /// Target vertex. + /// is . + /// is . + /// is not part of . + /// is not part of . + /// Something went wrong when running the algorithm. public void Compute([NotNull] TVertex root, [NotNull] TVertex target) { if (root == null) diff --git a/src/QuikGraph/Algorithms/Search/BestFirstFrontierSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/BestFirstFrontierSearchAlgorithm.cs index 0f598e5b3..31427edbe 100644 --- a/src/QuikGraph/Algorithms/Search/BestFirstFrontierSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/BestFirstFrontierSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -33,6 +33,9 @@ public sealed class BestFirstFrontierSearchAlgorithm /// Graph to visit. /// Function that for a given edge provide its weight. /// Distance relaxer. + /// is . + /// is . + /// is . public BestFirstFrontierSearchAlgorithm( [NotNull] IBidirectionalIncidenceGraph visitedGraph, [NotNull] Func edgeWeights, @@ -48,6 +51,9 @@ public BestFirstFrontierSearchAlgorithm( /// Graph to visit. /// Function that for a given edge provide its weight. /// Distance relaxer. + /// is . + /// is . + /// is . public BestFirstFrontierSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IBidirectionalIncidenceGraph visitedGraph, @@ -143,7 +149,9 @@ private void ExpandNode( // as used in any of the copies operators[edge] = GraphColor.Gray; if (open.MinimumUpdate(nCost, edge.Target)) + { OnTreeEdge(edge); + } } else { diff --git a/src/QuikGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs index 0ca07069c..f6068345a 100644 --- a/src/QuikGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/BidirectionalDepthFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -26,6 +26,7 @@ public sealed class BidirectionalDepthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public BidirectionalDepthFirstSearchAlgorithm( [NotNull] IBidirectionalGraph visitedGraph) : this(visitedGraph, new Dictionary()) @@ -37,6 +38,8 @@ public BidirectionalDepthFirstSearchAlgorithm( /// /// Graph to visit. /// Vertices associated to their colors (treatment states). + /// is . + /// is . public BidirectionalDepthFirstSearchAlgorithm( [NotNull] IBidirectionalGraph visitedGraph, [NotNull] IDictionary verticesColors) @@ -50,6 +53,8 @@ public BidirectionalDepthFirstSearchAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Vertices associated to their colors (treatment states). + /// is . + /// is . public BidirectionalDepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IBidirectionalGraph visitedGraph, @@ -71,11 +76,12 @@ public BidirectionalDepthFirstSearchAlgorithm( /// Gets or sets the maximum exploration depth, from the start vertex. /// /// - /// Defaulted at . + /// Defaulted to . /// /// /// Maximum exploration depth. /// + /// Value is negative or equal to 0. public int MaxDepth { get => _maxDepth; @@ -209,7 +215,9 @@ protected override void InternalCompute() Visit(root, 0); if (ProcessAllComponents) + { VisitAllWhiteVertices(); // All remaining vertices (because there are not white marked) + } } else { diff --git a/src/QuikGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs index 953cc9bff..1bb3987df 100644 --- a/src/QuikGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/BreadthFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -30,6 +30,7 @@ public sealed class BreadthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public BreadthFirstSearchAlgorithm([NotNull] IVertexListGraph visitedGraph) : this(visitedGraph, new Collections.Queue(), new Dictionary()) { @@ -41,6 +42,9 @@ public BreadthFirstSearchAlgorithm([NotNull] IVertexListGraph vi /// Graph to visit. /// Queue of vertices to treat. /// Vertices associated to their colors (treatment states). + /// is . + /// is . + /// is . public BreadthFirstSearchAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] IQueue vertexQueue, @@ -56,6 +60,9 @@ public BreadthFirstSearchAlgorithm( /// Graph to visit. /// Queue of vertices to treat. /// Vertices associated to their colors (treatment states). + /// is . + /// is . + /// is . public BreadthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -73,6 +80,10 @@ public BreadthFirstSearchAlgorithm( /// Queue of vertices to treat. /// Vertices associated to their colors (treatment states). /// Function that is used filter out-edges of a vertex. + /// is . + /// is . + /// is . + /// is . public BreadthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -244,7 +255,9 @@ protected override void InternalCompute() { // Enqueue roots foreach (TVertex root in VisitedGraph.Roots()) + { EnqueueRoot(root); + } } FlushVisitQueue(); @@ -313,9 +326,13 @@ private void FlushVisitQueue() { OnNonTreeEdge(edge); if (vColor == GraphColor.Gray) + { OnGrayTarget(edge); + } else + { OnBlackTarget(edge); + } } } diff --git a/src/QuikGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs index 99d1e048e..7bd893194 100644 --- a/src/QuikGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/DepthFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -23,6 +23,7 @@ public sealed class DepthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public DepthFirstSearchAlgorithm([NotNull] IVertexListGraph visitedGraph) : this(visitedGraph, new Dictionary()) { @@ -33,6 +34,8 @@ public DepthFirstSearchAlgorithm([NotNull] IVertexListGraph visi /// /// Graph to visit. /// Vertices associated to their colors (treatment states). + /// is . + /// is . public DepthFirstSearchAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] IDictionary verticesColors) @@ -45,6 +48,7 @@ public DepthFirstSearchAlgorithm( /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . public DepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph) @@ -58,6 +62,8 @@ public DepthFirstSearchAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Vertices associated to their colors (treatment states). + /// is . + /// is . public DepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -76,6 +82,9 @@ public DepthFirstSearchAlgorithm( /// Delegate that takes the enumeration of out-edges and filters/reorders /// them. All vertices passed to the method should be enumerated once and only once. /// + /// is . + /// is . + /// is . public DepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -105,11 +114,12 @@ public DepthFirstSearchAlgorithm( /// Gets or sets the maximum exploration depth, from the start vertex. /// /// - /// Defaulted at . + /// Defaulted to . /// /// /// Maximum exploration depth. /// + /// Value is negative or equal to 0. public int MaxDepth { get => _maxDepth; @@ -243,7 +253,9 @@ protected override void InternalCompute() Visit(root); if (ProcessAllComponents) + { VisitAllWhiteVertices(); // All remaining vertices (because there are not white marked) + } } else { @@ -320,7 +332,7 @@ private void Visit([NotNull] TVertex root) VerticesColors[root] = GraphColor.Gray; OnDiscoverVertex(root); - var enumerable = OutEdgesFilter(VisitedGraph.OutEdges(root)); + IEnumerable enumerable = OutEdgesFilter(VisitedGraph.OutEdges(root)); todoStack.Push(new SearchFrame(root, enumerable.GetEnumerator(), 0)); while (todoStack.Count > 0) diff --git a/src/QuikGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs index 095c4e450..aff79e56b 100644 --- a/src/QuikGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/EdgeDepthFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -26,6 +26,7 @@ public sealed class EdgeDepthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public EdgeDepthFirstSearchAlgorithm( [NotNull] IEdgeListAndIncidenceGraph visitedGraph) : this(visitedGraph, new Dictionary()) @@ -37,6 +38,8 @@ public EdgeDepthFirstSearchAlgorithm( /// /// Graph to visit. /// Edges associated to their colors (treatment states). + /// is . + /// is . public EdgeDepthFirstSearchAlgorithm( [NotNull] IEdgeListAndIncidenceGraph visitedGraph, [NotNull] IDictionary edgesColors) @@ -50,6 +53,8 @@ public EdgeDepthFirstSearchAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Edges associated to their colors (treatment states). + /// is . + /// is . public EdgeDepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IEdgeListAndIncidenceGraph visitedGraph, @@ -71,11 +76,12 @@ public EdgeDepthFirstSearchAlgorithm( /// Gets or sets the maximum exploration depth, from the start vertex. /// /// - /// Defaulted at . + /// Defaulted to . /// /// /// Maximum exploration depth. /// + /// Value is negative or equal to 0. public int MaxDepth { get => _maxDepth; @@ -216,7 +222,9 @@ protected override void InternalCompute() // Process the rest of the graph edges if (ProcessAllComponents) + { VisitAllWhiteEdges(); + } } else { diff --git a/src/QuikGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs index 448ee7d07..f3854a482 100644 --- a/src/QuikGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/ImplicitDepthFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -21,6 +21,7 @@ public sealed class ImplicitDepthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public ImplicitDepthFirstSearchAlgorithm( [NotNull] IIncidenceGraph visitedGraph) : this(null, visitedGraph) @@ -32,6 +33,7 @@ public ImplicitDepthFirstSearchAlgorithm( /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . public ImplicitDepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IIncidenceGraph visitedGraph) @@ -51,11 +53,12 @@ public ImplicitDepthFirstSearchAlgorithm( /// Gets or sets the maximum exploration depth, from the start vertex. /// /// - /// Defaulted at . + /// Defaulted to . /// /// /// Maximum exploration depth. /// + /// Value is negative or equal to 0. public int MaxDepth { get => _maxDepth; diff --git a/src/QuikGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs index d213b8486..1b6a68b40 100644 --- a/src/QuikGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/ImplicitEdgeDepthFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -24,6 +24,7 @@ public sealed class ImplicitEdgeDepthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public ImplicitEdgeDepthFirstSearchAlgorithm( [NotNull] IIncidenceGraph visitedGraph) : this(null, visitedGraph) @@ -35,6 +36,7 @@ public ImplicitEdgeDepthFirstSearchAlgorithm( /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . public ImplicitEdgeDepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IIncidenceGraph visitedGraph) @@ -48,11 +50,12 @@ public ImplicitEdgeDepthFirstSearchAlgorithm( /// Gets or sets the maximum exploration depth, from the start vertex. /// /// - /// Defaulted at . + /// Defaulted to . /// /// /// Maximum exploration depth. /// + /// Value is negative or equal to 0. public int MaxDepth { get => _maxDepth; @@ -226,9 +229,13 @@ private void Visit([NotNull] TEdge startingEdge, int depth) else { if (color == GraphColor.Gray) + { OnBackEdge(edge); + } else + { OnForwardOrCrossEdge(edge); + } } } diff --git a/src/QuikGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs index cca5c1c70..f5e4a6e67 100644 --- a/src/QuikGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/UndirectedBreathFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -26,6 +26,7 @@ public sealed class UndirectedBreadthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public UndirectedBreadthFirstSearchAlgorithm( [NotNull] IUndirectedGraph visitedGraph) : this(visitedGraph, new Collections.Queue(), new Dictionary()) @@ -38,6 +39,9 @@ public UndirectedBreadthFirstSearchAlgorithm( /// Graph to visit. /// Queue of vertices to treat. /// Vertices associated to their colors (treatment states). + /// is . + /// is . + /// is . public UndirectedBreadthFirstSearchAlgorithm( [NotNull] IUndirectedGraph visitedGraph, [NotNull] IQueue vertexQueue, @@ -53,6 +57,9 @@ public UndirectedBreadthFirstSearchAlgorithm( /// Graph to visit. /// Queue of vertices to treat. /// Vertices associated to their colors (treatment states). + /// is . + /// is . + /// is . public UndirectedBreadthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, @@ -290,9 +297,13 @@ private void ExploreAdjacentEdges([NotNull] TVertex u) { OnNonTreeEdge(edge, reversed); if (vColor == GraphColor.Gray) + { OnGrayTarget(edge, reversed); + } else + { OnBlackTarget(edge, reversed); + } } } } diff --git a/src/QuikGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs b/src/QuikGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs index c0e304c63..3cd4eafa3 100644 --- a/src/QuikGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs +++ b/src/QuikGraph/Algorithms/Search/UndirectedDepthFirstSearchAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -23,6 +23,7 @@ public sealed class UndirectedDepthFirstSearchAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public UndirectedDepthFirstSearchAlgorithm( [NotNull] IUndirectedGraph visitedGraph) : this(visitedGraph, new Dictionary()) @@ -34,6 +35,8 @@ public UndirectedDepthFirstSearchAlgorithm( /// /// Graph to visit. /// Vertices associated to their colors (treatment states). + /// is . + /// is . public UndirectedDepthFirstSearchAlgorithm( [NotNull] IUndirectedGraph visitedGraph, [NotNull] IDictionary verticesColors) @@ -47,6 +50,8 @@ public UndirectedDepthFirstSearchAlgorithm( /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Vertices associated to their colors (treatment states). + /// is . + /// is . public UndirectedDepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, @@ -65,6 +70,9 @@ public UndirectedDepthFirstSearchAlgorithm( /// Delegate that takes the enumeration of out-edges and filters/reorders /// them. All vertices passed to the method should be enumerated once and only once. /// + /// is . + /// is . + /// is . public UndirectedDepthFirstSearchAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, @@ -94,11 +102,12 @@ public UndirectedDepthFirstSearchAlgorithm( /// Gets or sets the maximum exploration depth, from the start vertex. /// /// - /// Defaulted at . + /// Defaulted to . /// /// /// Maximum exploration depth. /// + /// Value is negative or equal to 0. public int MaxDepth { get => _maxDepth; @@ -251,7 +260,9 @@ protected override void InternalCompute() Visit(root); if (ProcessAllComponents) + { VisitAllWhiteVertices(); // All remaining vertices (because there are not white marked) + } } else { diff --git a/src/QuikGraph/Algorithms/Services/AlgorithmServices.cs b/src/QuikGraph/Algorithms/Services/AlgorithmServices.cs index 87726169e..960bc15d9 100644 --- a/src/QuikGraph/Algorithms/Services/AlgorithmServices.cs +++ b/src/QuikGraph/Algorithms/Services/AlgorithmServices.cs @@ -1,5 +1,4 @@ - -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Algorithms.Services @@ -16,6 +15,7 @@ internal sealed class AlgorithmServices : IAlgorithmServices /// Initializes a new instance of the class. /// /// Algorithm host. + /// is . public AlgorithmServices([NotNull] IAlgorithmComponent host) { _host = host ?? throw new ArgumentNullException(nameof(host)); diff --git a/src/QuikGraph/Algorithms/Services/CancelManager.cs b/src/QuikGraph/Algorithms/Services/CancelManager.cs index 5107b6d8a..531dcf3ee 100644 --- a/src/QuikGraph/Algorithms/Services/CancelManager.cs +++ b/src/QuikGraph/Algorithms/Services/CancelManager.cs @@ -16,7 +16,9 @@ public void Cancel() { int value = Interlocked.Increment(ref _cancelling); if (value == 0) + { CancelRequested?.Invoke(this, EventArgs.Empty); + } } private int _cancelling; @@ -32,7 +34,9 @@ public void ResetCancel() { int value = Interlocked.Exchange(ref _cancelling, 0); if (value != 0) + { CancelReset?.Invoke(this, EventArgs.Empty); + } } } } \ No newline at end of file diff --git a/src/QuikGraph/Algorithms/ShortestPath/AStarShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/AStarShortestPathAlgorithm.cs index 26c25ccf7..b8e089af6 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/AStarShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/AStarShortestPathAlgorithm.cs @@ -29,6 +29,9 @@ public sealed class AStarShortestPathAlgorithm /// Graph to visit. /// Function that computes the weight for a given edge. /// Function that computes a cost for a given vertex. + /// is . + /// is . + /// is . public AStarShortestPathAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] Func edgeWeights, @@ -44,6 +47,10 @@ public AStarShortestPathAlgorithm( /// Function that computes the weight for a given edge. /// Function that computes a cost for a given vertex. /// Distance relaxer. + /// is . + /// is . + /// is . + /// is . public AStarShortestPathAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] Func edgeWeights, @@ -61,6 +68,10 @@ public AStarShortestPathAlgorithm( /// Function that computes the weight for a given edge. /// Function that computes a cost for a given vertex. /// Distance relaxer. + /// is . + /// is . + /// is . + /// is . public AStarShortestPathAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -219,7 +230,9 @@ protected override void InternalCompute() foreach (TVertex vertex in VisitedGraph.Vertices) { if (VerticesColors[vertex] == GraphColor.White) + { ComputeFromRoot(vertex); + } } } } diff --git a/src/QuikGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs index 412c0ac12..2ef3f5fa5 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs @@ -35,6 +35,8 @@ public sealed class BellmanFordShortestPathAlgorithm /// /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public BellmanFordShortestPathAlgorithm( [NotNull] IVertexAndEdgeListGraph visitedGraph, [NotNull] Func edgeWeights) @@ -48,6 +50,9 @@ public BellmanFordShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public BellmanFordShortestPathAlgorithm( [NotNull] IVertexAndEdgeListGraph visitedGraph, [NotNull] Func edgeWeights, @@ -63,6 +68,9 @@ public BellmanFordShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public BellmanFordShortestPathAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexAndEdgeListGraph visitedGraph, @@ -209,12 +217,11 @@ protected override void InternalCompute() break; } - IDistanceRelaxer relaxer = DistanceRelaxer; foreach (TEdge edge in VisitedGraph.Edges) { double edgeWeight = Weights(edge); - if (relaxer.Compare( - relaxer.Combine(GetVertexDistance(edge.Source), edgeWeight), + if (DistanceRelaxer.Compare( + DistanceRelaxer.Combine(GetVertexDistance(edge.Source), edgeWeight), GetVertexDistance(edge.Target)) < 0) { OnEdgeMinimized(edge); diff --git a/src/QuikGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs index 2d2a22c72..b525c2be1 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/DagShortestPathAlgorithm.cs @@ -22,6 +22,8 @@ public sealed class DagShortestPathAlgorithm /// /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public DagShortestPathAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] Func edgeWeights) @@ -35,6 +37,9 @@ public DagShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public DagShortestPathAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] Func edgeWeights, @@ -50,6 +55,9 @@ public DagShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public DagShortestPathAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -187,9 +195,13 @@ private void ComputeNoInit([NotNull] TVertex root) bool decreased = Relax(edge); if (decreased) + { OnTreeEdge(edge); + } else + { OnEdgeNotRelaxed(edge); + } } VerticesColors[vertex] = GraphColor.Black; diff --git a/src/QuikGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs index 4286e80f1..9d416e931 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/DijkstraShortestPathAlgorithm.cs @@ -26,6 +26,8 @@ public sealed class DijkstraShortestPathAlgorithm /// /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public DijkstraShortestPathAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] Func edgeWeights) @@ -39,6 +41,9 @@ public DijkstraShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public DijkstraShortestPathAlgorithm( [NotNull] IVertexListGraph visitedGraph, [NotNull] Func edgeWeights, @@ -54,6 +59,9 @@ public DijkstraShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public DijkstraShortestPathAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph, @@ -188,7 +196,9 @@ protected override void InternalCompute() foreach (TVertex vertex in VisitedGraph.Vertices) { if (VerticesColors[vertex] == GraphColor.White) + { ComputeFromRoot(vertex); + } } } } diff --git a/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs index 90a54ef5f..3d3f0357d 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -81,6 +81,8 @@ public override string ToString() /// /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public FloydWarshallAllShortestPathAlgorithm( [NotNull] IVertexAndEdgeListGraph visitedGraph, [NotNull] Func edgeWeights) @@ -94,6 +96,9 @@ public FloydWarshallAllShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public FloydWarshallAllShortestPathAlgorithm( [NotNull] IVertexAndEdgeListGraph visitedGraph, [NotNull] Func edgeWeights, @@ -109,6 +114,9 @@ public FloydWarshallAllShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public FloydWarshallAllShortestPathAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexAndEdgeListGraph visitedGraph, @@ -129,6 +137,8 @@ public FloydWarshallAllShortestPathAlgorithm( /// Target vertex. /// Associated distance (cost). /// True if the distance was found, false otherwise. + /// is . + /// is . public bool TryGetDistance([NotNull] TVertex source, [NotNull] TVertex target, out double distance) { if (source == null) @@ -154,6 +164,10 @@ public bool TryGetDistance([NotNull] TVertex source, [NotNull] TVertex target, o /// Target vertex. /// The found path, otherwise null. /// True if a path linking both vertices was found, false otherwise. + /// is . + /// is . + /// Failed to find a predecessor vertex while getting path. + [ContractAnnotation("=> true, path:notnull;=> false, path:null")] public bool TryGetPath( [NotNull] TVertex source, [NotNull] TVertex target, @@ -173,6 +187,7 @@ public bool TryGetPath( return TryGetPathInternal(source, target, out path); } + [ContractAnnotation("=> true, path:notnull;=> false, path:null")] private bool TryGetPathInternal( [NotNull] TVertex source, [NotNull] TVertex target, @@ -246,9 +261,13 @@ protected override void Initialize() SEquatableEdge ij = edge.ToVertexPair(); double cost = _weights(edge); if (!_data.TryGetValue(ij, out VertexData data)) + { _data[ij] = new VertexData(cost, edge); + } else if (cost < data.Distance) + { _data[ij] = new VertexData(cost, edge); + } } } @@ -261,7 +280,9 @@ protected override void InternalCompute() // Walk each vertices and make sure cost self-cost 0 foreach (TVertex vertex in vertices) + { _data[new SEquatableEdge(vertex, vertex)] = new VertexData(0, default(TEdge)); + } ThrowIfCancellationRequested(); diff --git a/src/QuikGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs b/src/QuikGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs index 103dcbc52..25dfcd1bd 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/ShortestPathAlgorithmBase.cs @@ -32,6 +32,8 @@ public abstract class ShortestPathAlgorithmBase /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . protected ShortestPathAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] TGraph visitedGraph, @@ -47,6 +49,9 @@ protected ShortestPathAlgorithmBase( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . protected ShortestPathAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] TGraph visitedGraph, @@ -85,6 +90,7 @@ protected void SetVertexDistance([NotNull] TVertex vertex, double distance) } /// + /// Algorithm has not been run. public bool TryGetDistance(TVertex vertex, out double distance) { if (vertex == null) @@ -96,6 +102,7 @@ public bool TryGetDistance(TVertex vertex, out double distance) } /// + /// Algorithm has not been run. public double GetDistance(TVertex vertex) { bool vertexFound = TryGetDistance(vertex, out double distance); diff --git a/src/QuikGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs index 8ede72bc6..acf552151 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/UndirectedDijkstraShortestPathAlgorithm.cs @@ -26,6 +26,8 @@ public sealed class UndirectedDijkstraShortestPathAlgorithm /// /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public UndirectedDijkstraShortestPathAlgorithm( [NotNull] IUndirectedGraph visitedGraph, [NotNull] Func edgeWeights) @@ -39,6 +41,9 @@ public UndirectedDijkstraShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public UndirectedDijkstraShortestPathAlgorithm( [NotNull] IUndirectedGraph visitedGraph, [NotNull] Func edgeWeights, @@ -54,6 +59,9 @@ public UndirectedDijkstraShortestPathAlgorithm( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . public UndirectedDijkstraShortestPathAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, @@ -175,7 +183,9 @@ protected override void InternalCompute() foreach (TVertex vertex in VisitedGraph.Vertices) { if (VerticesColors[vertex] == GraphColor.White) + { ComputeFromRoot(vertex); + } } } } diff --git a/src/QuikGraph/Algorithms/ShortestPath/UndirectedShortestPathAlgorithmBase.cs b/src/QuikGraph/Algorithms/ShortestPath/UndirectedShortestPathAlgorithmBase.cs index e52f52c61..1b6f22bfd 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/UndirectedShortestPathAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/UndirectedShortestPathAlgorithmBase.cs @@ -30,6 +30,8 @@ public abstract class UndirectedShortestPathAlgorithmBase /// Host to use if set, otherwise use this reference. /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . protected UndirectedShortestPathAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, @@ -45,6 +47,9 @@ protected UndirectedShortestPathAlgorithmBase( /// Graph to visit. /// Function that computes the weight for a given edge. /// Distance relaxer. + /// is . + /// is . + /// is . protected UndirectedShortestPathAlgorithmBase( [CanBeNull] IAlgorithmComponent host, [NotNull] IUndirectedGraph visitedGraph, @@ -83,6 +88,7 @@ protected void SetVertexDistance([NotNull] TVertex vertex, double distance) } /// + /// Algorithm has not been run. public bool TryGetDistance(TVertex vertex, out double distance) { if (vertex == null) @@ -94,6 +100,7 @@ public bool TryGetDistance(TVertex vertex, out double distance) } /// + /// Algorithm has not been run. public double GetDistance(TVertex vertex) { bool vertexFound = TryGetDistance(vertex, out double distance); @@ -188,7 +195,7 @@ protected virtual void OnTreeEdge([NotNull] TEdge edge, bool reversed) /// Source vertex. /// Target vertex. /// True if relaxation decreased the target vertex distance, false otherwise. - protected bool Relax(TEdge edge, TVertex source, TVertex target) + protected bool Relax([NotNull] TEdge edge, [NotNull] TVertex source, [NotNull] TVertex target) { Debug.Assert(edge != null); Debug.Assert(source != null); @@ -204,9 +211,8 @@ protected bool Relax(TEdge edge, TVertex source, TVertex target) double dv = GetVertexDistance(target); double we = Weights(edge); - IDistanceRelaxer relaxer = DistanceRelaxer; - double duwe = relaxer.Combine(du, we); - if (relaxer.Compare(duwe, dv) < 0) + double duwe = DistanceRelaxer.Combine(du, we); + if (DistanceRelaxer.Compare(duwe, dv) < 0) { SetVertexDistance(target, duwe); return true; diff --git a/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs index 4315ce555..b2c30b51f 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/YenShortestPathsAlgorithm.cs @@ -60,7 +60,9 @@ internal EquatableTaggedEdge GetEdge(int i) internal EquatableTaggedEdge[] GetEdges(int count) { if (count > _edges.Count) + { count = _edges.Count; + } Debug.Assert(count >= 0 && count <= _edges.Count); @@ -117,7 +119,7 @@ IEnumerator IEnumerable.GetEnumerator() /// Initializes a new instance of the class. /// /// - /// for tag type (edge) which comes from Dijkstra’s algorithm, which is used to get one shortest path. + /// for tag type (edge) which comes from Dijkstra’s algorithm, which is used to get one shortest path. /// /// Graph to visit. /// Source vertex. @@ -125,6 +127,12 @@ IEnumerator IEnumerable.GetEnumerator() /// Maximum number of path to search. /// Optional function that computes the weight for a given edge. /// Optional filter of found paths. + /// is . + /// is . + /// is . + /// is not part of . + /// is not part of . + /// is lower than 1. public YenShortestPathsAlgorithm( [NotNull] AdjacencyGraph> graph, [NotNull] TVertex source, @@ -139,6 +147,10 @@ public YenShortestPathsAlgorithm( throw new ArgumentNullException(nameof(source)); if (target == null) throw new ArgumentNullException(nameof(target)); + if (!graph.ContainsVertex(source)) + throw new ArgumentException("Source must be in the graph", nameof(source)); + if (!graph.ContainsVertex(target)) + throw new ArgumentException("Target must be in the graph", nameof(source)); if (k < 1) throw new ArgumentOutOfRangeException(nameof(k), "Value must be positive."); @@ -169,18 +181,9 @@ private double GetPathDistance([ItemNotNull] SortedPath edges) return edges.Sum(edge => _weights(edge)); } - private void AssertSourceAndTargetInGraph() - { - // In case the root or target vertex is not in the graph then there is no path found - if (!_graph.ContainsVertex(_sourceVertex) || !_graph.ContainsVertex(_targetVertex)) - throw new NoPathFoundException(); - } - [Pure] private SortedPath GetInitialShortestPath() { - AssertSourceAndTargetInGraph(); - // Find the first shortest way from source to target SortedPath? shortestPath = GetShortestPathInGraph(_graph, _sourceVertex, _targetVertex); // In case of Dijkstra’s algorithm couldn't find any ways @@ -206,7 +209,9 @@ private SortedPath GetInitialShortestPath() var recorder = new VertexPredecessorRecorderObserver>(); using (recorder.Attach(algorithm)) + { algorithm.Compute(source); + } // Get shortest path from start (source) vertex to target return recorder.TryGetPath(target, out IEnumerable> path) @@ -284,7 +289,9 @@ private bool SearchAndAddKthShortestPath( // Add the potential k-shortest path to the heap if (!shortestPathCandidates.Contains(totalPath)) + { shortestPathCandidates.Enqueue(totalPath); + } } // Add back the edges and nodes that were removed from the graph @@ -313,6 +320,7 @@ private bool SearchAndAddKthShortestPath( /// Runs the algorithm. /// /// Found paths. + /// No shortest path was found. [Pure] [NotNull] public IEnumerable Execute() diff --git a/src/QuikGraph/Algorithms/TSP/TSP.cs b/src/QuikGraph/Algorithms/TSP/TSP.cs index bbc90aa88..8bf39ed0a 100644 --- a/src/QuikGraph/Algorithms/TSP/TSP.cs +++ b/src/QuikGraph/Algorithms/TSP/TSP.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; using QuikGraph.Algorithms.ShortestPath; @@ -36,6 +36,8 @@ public class TSP : ShortestPathAlgorithmBase /// Graph to visit. /// Function that computes the weight for a given edge. + /// is . + /// is . public TSP( [NotNull] TGraph visitedGraph, [NotNull] Func edgeWeights) diff --git a/src/QuikGraph/Algorithms/TSP/TasksManager.cs b/src/QuikGraph/Algorithms/TSP/TasksManager.cs index 7ba9f9801..e9fe385f3 100644 --- a/src/QuikGraph/Algorithms/TSP/TasksManager.cs +++ b/src/QuikGraph/Algorithms/TSP/TasksManager.cs @@ -33,6 +33,7 @@ public void AddTask([NotNull] Task task) /// Gets and removes the task with minimal priority. /// /// The . + [Pure] [NotNull] public Task GetTask() { diff --git a/src/QuikGraph/Algorithms/TarjanOfflineLeastCommonAncestorAlgorithm.cs b/src/QuikGraph/Algorithms/TarjanOfflineLeastCommonAncestorAlgorithm.cs index d77e23a12..e705b3fb1 100644 --- a/src/QuikGraph/Algorithms/TarjanOfflineLeastCommonAncestorAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TarjanOfflineLeastCommonAncestorAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -38,6 +38,7 @@ public sealed class TarjanOfflineLeastCommonAncestorAlgorithm /// Initializes a new instance of the class. /// /// Graph to visit. + /// is . public TarjanOfflineLeastCommonAncestorAlgorithm( [NotNull] IVertexListGraph visitedGraph) : this(null, visitedGraph) @@ -49,6 +50,7 @@ public TarjanOfflineLeastCommonAncestorAlgorithm( /// /// Host to use if set, otherwise use this reference. /// Graph to visit. + /// is . public TarjanOfflineLeastCommonAncestorAlgorithm( [CanBeNull] IAlgorithmComponent host, [NotNull] IVertexListGraph visitedGraph) @@ -115,6 +117,7 @@ protected override void InternalCompute() /// Vertices pairs if set. /// True if vertex pairs were set, false otherwise. [Pure] + [ContractAnnotation("=> true, pairs:notnull;=> false, pairs:null")] public bool TryGetVertexPairs(out IEnumerable> pairs) { pairs = _pairs; @@ -125,6 +128,8 @@ public bool TryGetVertexPairs(out IEnumerable> pairs) /// Sets vertices pairs. /// /// Vertices pairs. + /// is . + /// is empty or any vertex from pairs is not part of . public void SetVertexPairs([NotNull] IEnumerable> pairs) { if (pairs is null) @@ -145,6 +150,10 @@ public void SetVertexPairs([NotNull] IEnumerable> pairs) /// /// Root vertex. /// Vertices pairs. + /// is . + /// is . + /// is not part of . + /// is empty or any vertex from pairs is not part of . public void Compute([NotNull] TVertex root, [NotNull] IEnumerable> pairs) { SetVertexPairs(pairs); diff --git a/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstBidirectionalTopologicalSortAlgorithm.cs b/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstBidirectionalTopologicalSortAlgorithm.cs index b080819ff..4a17f12fd 100644 --- a/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstBidirectionalTopologicalSortAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstBidirectionalTopologicalSortAlgorithm.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using JetBrains.Annotations; @@ -27,6 +27,7 @@ public sealed class SourceFirstBidirectionalTopologicalSortAlgorithm /// Graph to visit. /// Sorted vertices capacity. + /// is . public SourceFirstBidirectionalTopologicalSortAlgorithm( [NotNull] IBidirectionalGraph visitedGraph, int capacity = -1) @@ -40,6 +41,7 @@ public SourceFirstBidirectionalTopologicalSortAlgorithm( /// Graph to visit. /// Sort direction. /// Sorted vertices capacity. + /// is . public SourceFirstBidirectionalTopologicalSortAlgorithm( [NotNull] IBidirectionalGraph visitedGraph, TopologicalSortDirection direction, @@ -58,7 +60,7 @@ public SourceFirstBidirectionalTopologicalSortAlgorithm( public TVertex[] SortedVertices { get; private set; } /// - /// Vertices in degrees. + /// Vertices in-degrees. /// [NotNull] public IDictionary InDegrees { get; } = new Dictionary(); diff --git a/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs b/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs index 744c90162..58a898a96 100644 --- a/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TopologicalSort/SourceFirstTopologicalSortAlgorithm.cs @@ -25,6 +25,7 @@ public sealed class SourceFirstTopologicalSortAlgorithm : Algori /// /// Graph to visit. /// Sorted vertices capacity. + /// is . public SourceFirstTopologicalSortAlgorithm( [NotNull] IVertexAndEdgeListGraph visitedGraph, int capacity = -1) @@ -41,7 +42,7 @@ public SourceFirstTopologicalSortAlgorithm( public TVertex[] SortedVertices { get; private set; } /// - /// Vertices in degrees. + /// Vertices in-degrees. /// [NotNull] public IDictionary InDegrees { get; } = new Dictionary(); diff --git a/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs b/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs index b3c58c558..7a34a9448 100644 --- a/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using JetBrains.Annotations; @@ -24,6 +24,7 @@ public sealed class TopologicalSortAlgorithm /// /// Graph to visit. /// Sorted vertices capacity. + /// is . public TopologicalSortAlgorithm( [NotNull] IVertexListGraph visitedGraph, int capacity = -1) diff --git a/src/QuikGraph/Algorithms/TopologicalSort/UndirectedFirstTopologicalSortAlgorithm.cs b/src/QuikGraph/Algorithms/TopologicalSort/UndirectedFirstTopologicalSortAlgorithm.cs index 18bfff4c3..3a0fcf314 100644 --- a/src/QuikGraph/Algorithms/TopologicalSort/UndirectedFirstTopologicalSortAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TopologicalSort/UndirectedFirstTopologicalSortAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -26,6 +26,7 @@ public sealed class UndirectedFirstTopologicalSortAlgorithm : Al /// /// Graph to visit. /// Sorted vertices capacity. + /// is . public UndirectedFirstTopologicalSortAlgorithm( [NotNull] IUndirectedGraph visitedGraph, int capacity = -1) @@ -126,7 +127,9 @@ void UpdateAdjacentDegree(TVertex vertex) throw new InvalidOperationException("Degree is negative, and cannot be."); if (_heap.Contains(other)) + { _heap.Update(other); + } } } diff --git a/src/QuikGraph/Algorithms/TopologicalSort/UndirectedTopologicalSortAlgorithm.cs b/src/QuikGraph/Algorithms/TopologicalSort/UndirectedTopologicalSortAlgorithm.cs index 078f74500..2ca414dd5 100644 --- a/src/QuikGraph/Algorithms/TopologicalSort/UndirectedTopologicalSortAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TopologicalSort/UndirectedTopologicalSortAlgorithm.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using QuikGraph.Algorithms.Search; @@ -21,6 +21,7 @@ public sealed class UndirectedTopologicalSortAlgorithm : Algorit /// /// Graph to visit. /// Sorted vertices capacity. + /// is . public UndirectedTopologicalSortAlgorithm( [NotNull] IUndirectedGraph visitedGraph, int capacity = -1) diff --git a/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs b/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs index 967f6d597..79de5e3bf 100644 --- a/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Algorithms @@ -17,6 +17,8 @@ public class TransitiveClosureAlgorithm : AlgorithmBase /// Graph to visit. /// Function that create an edge between the 2 given vertices. + /// is . + /// is . public TransitiveClosureAlgorithm( [NotNull] BidirectionalGraph visitedGraph, [NotNull] Func edgeFactory) @@ -47,7 +49,9 @@ protected override void InternalCompute() algorithmHelper.InternalCompute((graph, u, v, found, edge) => { if (!found) + { graph.AddEdge(_createEdge(u, v)); + } }); } diff --git a/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs b/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs index 3eccdedf4..5cb043be8 100644 --- a/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs @@ -1,9 +1,4 @@ -/* - * Code by Yoad Snapir with a bit of refactoring. - * Taken from https://github.com/yoadsn/ArrowDiagramGenerator because PR was not opened. - **/ - -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph.Algorithms { @@ -20,6 +15,7 @@ public class TransitiveReductionAlgorithm : AlgorithmBase class. /// /// Graph to visit. + /// is . public TransitiveReductionAlgorithm( [NotNull] BidirectionalGraph visitedGraph) : base(visitedGraph) @@ -46,7 +42,9 @@ protected override void InternalCompute() algorithmHelper.InternalCompute((graph, u, v, found, edge) => { if (found) + { graph.RemoveEdge(edge); + } }); } diff --git a/src/QuikGraph/Algorithms/VertexColoration/VertexColoringAlgorithm.cs b/src/QuikGraph/Algorithms/VertexColoration/VertexColoringAlgorithm.cs index 78d1feef7..8988baded 100644 --- a/src/QuikGraph/Algorithms/VertexColoration/VertexColoringAlgorithm.cs +++ b/src/QuikGraph/Algorithms/VertexColoration/VertexColoringAlgorithm.cs @@ -17,6 +17,7 @@ public sealed class VertexColoringAlgorithm : AlgorithmBase class. /// /// Graph to visit. + /// is . public VertexColoringAlgorithm([NotNull] IUndirectedGraph visitedGraph) : base(visitedGraph) { diff --git a/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs b/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs index c4221c404..496ab5627 100644 --- a/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs +++ b/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using JetBrains.Annotations; using QuikGraph.Collections; @@ -30,6 +30,7 @@ public sealed class MinimumVertexCoverApproximationAlgorithm : A /// /// This constructor will use ad random number generator. /// Graph to compute the cover. + /// is . public MinimumVertexCoverApproximationAlgorithm( [NotNull] IUndirectedGraph graph) : this(graph, new CryptoRandom()) @@ -40,6 +41,7 @@ public MinimumVertexCoverApproximationAlgorithm( /// Initializes a new instance of the class. /// /// Graph to compute the cover. + /// is . public MinimumVertexCoverApproximationAlgorithm( [NotNull] IUndirectedGraph graph) : this(graph, new Random()) @@ -52,6 +54,8 @@ public MinimumVertexCoverApproximationAlgorithm( /// /// Graph to compute the cover. /// Random number generator. + /// is . + /// is . public MinimumVertexCoverApproximationAlgorithm( [NotNull] IUndirectedGraph graph, [NotNull] Random rng) diff --git a/src/QuikGraph/Collections/BinaryHeap.cs b/src/QuikGraph/Collections/BinaryHeap.cs index 0926d3af2..a15612e5c 100644 --- a/src/QuikGraph/Collections/BinaryHeap.cs +++ b/src/QuikGraph/Collections/BinaryHeap.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -49,6 +49,7 @@ public BinaryHeap() /// Initializes a new instance of the class. /// /// Heap capacity. + /// is negative. public BinaryHeap(int capacity) : this(capacity, Comparer.Default.Compare) { @@ -58,6 +59,7 @@ public BinaryHeap(int capacity) /// Initializes a new instance of the class. /// /// Priority comparer. + /// is . public BinaryHeap([NotNull] Comparison priorityComparison) : this(DefaultCapacity, priorityComparison) { @@ -68,6 +70,8 @@ public BinaryHeap([NotNull] Comparison priorityComparison) /// /// Heap capacity. /// Priority comparer. + /// is . + /// is negative. public BinaryHeap(int capacity, [NotNull] Comparison priorityComparison) { if (capacity < 0) @@ -173,7 +177,7 @@ private void MinHeapifyUp(int start) /// Gets the minimum pair. /// /// The minimal pair. - /// The heap is empty. + /// The heap is empty. public KeyValuePair Minimum() { if (Count == 0) @@ -185,7 +189,7 @@ public KeyValuePair Minimum() /// Gets and removes the minimal pair. /// /// The minimal pair. - /// The heap is empty. + /// The heap is empty. public KeyValuePair RemoveMinimum() { #if BINARY_HEAP_DEBUG @@ -220,9 +224,13 @@ private void MinHeapifyDown(int index) int right = 2 * index + 2; int smallest = index; if (left < Count && Less(left, smallest)) + { smallest = left; + } if (right < Count && Less(right, smallest)) + { smallest = right; + } if (smallest == index) break; @@ -266,14 +274,17 @@ public void Update([NotNull] TPriority priority, [NotNull] TValue value) // If it exists, update, else add if (index > -1) { - TPriority newPriority = priority; TPriority oldPriority = _items[index].Key; - _items[index] = new KeyValuePair(newPriority, value); + _items[index] = new KeyValuePair(priority, value); - if (PriorityComparison(newPriority, oldPriority) > 0) + if (PriorityComparison(priority, oldPriority) > 0) + { MinHeapifyDown(index); - else if (PriorityComparison(newPriority, oldPriority) < 0) + } + else if (PriorityComparison(priority, oldPriority) < 0) + { MinHeapifyUp(index); + } } else { @@ -394,7 +405,9 @@ public TValue[] ToArray() { var array = new TValue[Count]; for (int i = 0; i < Count; ++i) + { array[i] = _items[i].Value; + } return array; } @@ -421,25 +434,31 @@ private string EntryToString(int i) TPriority k = kvp.Key; TValue v = kvp.Value; - return $"{k.ToString()} {(v == null ? "null" : v.ToString())}"; + return $"{k} {(v == null ? "null" : v.ToString())}"; } /// /// Checks if this heap is consistent (fulfill indexing rule). /// /// True if the heap is consistent, false otherwise. + [Pure] internal bool IsConsistent() { int wrong = -1; - for (int i = 0; i < Count; i++) + for (int i = 0; i < Count; ++i) { int l = 2 * i + 1; int r = 2 * i + 2; if (l < Count && !LessOrEqual(i, l)) + { wrong = i; + } + if (r < Count && !LessOrEqual(i, r)) + { wrong = i; + } } bool correct = wrong == -1; diff --git a/src/QuikGraph/Collections/BinaryQueue.cs b/src/QuikGraph/Collections/BinaryQueue.cs index e4ef38177..43ac2804b 100644 --- a/src/QuikGraph/Collections/BinaryQueue.cs +++ b/src/QuikGraph/Collections/BinaryQueue.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -26,6 +26,7 @@ public sealed class BinaryQueue : IPriorityQueue /// Initializes a new instance of the class. /// /// Function that compute the distance for a given vertex. + /// is . public BinaryQueue([NotNull] Func distanceFunc) : this(distanceFunc, Comparer.Default.Compare) { @@ -36,6 +37,8 @@ public BinaryQueue([NotNull] Func distanceFunc) /// /// Function that compute the distance for a given vertex. /// Comparer of distances. + /// is . + /// is . public BinaryQueue( [NotNull] Func distanceFunc, [NotNull] Comparison distanceComparison) diff --git a/src/QuikGraph/Collections/EdgeEdgeDictionary.cs b/src/QuikGraph/Collections/EdgeEdgeDictionary.cs index df9374424..f1098b16b 100644 --- a/src/QuikGraph/Collections/EdgeEdgeDictionary.cs +++ b/src/QuikGraph/Collections/EdgeEdgeDictionary.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE +#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE using System; #endif using System.Collections.Generic; @@ -34,17 +34,13 @@ public EdgeEdgeDictionary() /// Initializes a new instance of the class. /// /// Dictionary capacity. + /// is negative. public EdgeEdgeDictionary(int capacity) : base(capacity) { } #if SUPPORTS_SERIALIZATION - /// - /// Initializes a new instance of with serialized data. - /// - /// that contains serialized data. - /// that contains contextual information. private EdgeEdgeDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { @@ -60,7 +56,9 @@ public EdgeEdgeDictionary Clone() { var clone = new EdgeEdgeDictionary(Count); foreach (KeyValuePair pair in this) + { clone.Add(pair.Key, pair.Value); + } return clone; } diff --git a/src/QuikGraph/Collections/EdgeList.cs b/src/QuikGraph/Collections/EdgeList.cs index 9ea916993..07f607ca3 100644 --- a/src/QuikGraph/Collections/EdgeList.cs +++ b/src/QuikGraph/Collections/EdgeList.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE +#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE using System; #endif using System.Collections.Generic; @@ -28,12 +28,14 @@ public EdgeList() /// Initializes a new instance of the class. /// /// List capacity. + /// is negative. public EdgeList(int capacity) : base(capacity) { } /// + /// is . public EdgeList([NotNull] EdgeList other) : base(other) { diff --git a/src/QuikGraph/Collections/FibonacciHeap.cs b/src/QuikGraph/Collections/FibonacciHeap.cs index a69637894..8656b4dc2 100644 --- a/src/QuikGraph/Collections/FibonacciHeap.cs +++ b/src/QuikGraph/Collections/FibonacciHeap.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -50,6 +50,7 @@ public FibonacciHeap(HeapDirection direction) /// /// Heap direction. /// Priority comparer. + /// is . public FibonacciHeap(HeapDirection direction, [NotNull] Comparison priorityComparison) { _cells = new FibonacciHeapLinkedList(); @@ -91,6 +92,7 @@ public FibonacciHeap(HeapDirection direction, [NotNull] Comparison pr /// /// Value priority. /// Value to add. + /// is . public FibonacciHeapCell Enqueue([NotNull] TPriority priority, [CanBeNull] TValue value) { if (priority == null) @@ -127,6 +129,8 @@ public FibonacciHeapCell Enqueue([NotNull] TPriority priority /// /// Cell to update the priority. /// New priority. + /// is . + /// is . public void ChangeKey([NotNull] FibonacciHeapCell cell, [NotNull] TPriority newPriority) { if (cell is null) @@ -225,7 +229,9 @@ private void UpdateCellOppositeDirection([NotNull] FibonacciHeapCell 0) { if (toUpdate is null) + { toUpdate = new List>(); + } toUpdate.Add(child); } } @@ -281,6 +287,7 @@ private void UpdateCellsDegree([NotNull] FibonacciHeapCell ce /// Deletes the given from this heap. /// /// Cell to delete. + /// is . public void Delete([NotNull] FibonacciHeapCell cell) { if (cell is null) @@ -294,6 +301,7 @@ public void Delete([NotNull] FibonacciHeapCell cell) /// Dequeues an element from the heap. /// /// Removed element. + /// The heap is empty. public KeyValuePair Dequeue() { if (Count == 0) @@ -355,7 +363,7 @@ private void CompressHeap() FibonacciHeapCell cell = _cells.First; while (cell != null) { - var nextCell = ReduceCell(ref cell); + FibonacciHeapCell nextCell = ReduceCell(ref cell); _degreeToCell[cell.Degree] = cell; cell = nextCell; @@ -422,7 +430,8 @@ private void ReduceCells( /// Merges the given into this heap. /// /// Heap to merge. - /// If the heap is not in the same direction. + /// is . + /// is not in the same direction as this heap. public void Merge([NotNull] FibonacciHeap heap) { if (heap is null) @@ -515,9 +524,7 @@ public string DrawHeap() { var lines = new List(); int columnPosition = 0; - var list = new List(); - foreach (FibonacciHeapCell cell in _cells) - list.Add(new CellLevel(cell, 0)); + var list = _cells.Select(cell => new CellLevel(cell, 0)).ToList(); list.Reverse(); var stack = new Stack(list); @@ -526,7 +533,9 @@ public string DrawHeap() CellLevel currentCell = stack.Pop(); int lineNum = currentCell.Level; if (lines.Count <= lineNum) + { lines.Add(string.Empty); + } string currentLine = lines[lineNum]; currentLine = currentLine.PadRight(columnPosition, ' '); diff --git a/src/QuikGraph/Collections/FibonacciHeapCell.cs b/src/QuikGraph/Collections/FibonacciHeapCell.cs index 8d6204dac..66b0372a9 100644 --- a/src/QuikGraph/Collections/FibonacciHeapCell.cs +++ b/src/QuikGraph/Collections/FibonacciHeapCell.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION +#if SUPPORTS_SERIALIZATION using System; #endif using System.Collections.Generic; @@ -66,9 +66,9 @@ public sealed class FibonacciHeapCell public FibonacciHeapCell Next { get; internal set; } /// - /// Converts this cell to a . + /// Converts this cell to a . /// - /// A corresponding . + /// A corresponding . [Pure] public KeyValuePair ToKeyValuePair() { diff --git a/src/QuikGraph/Collections/FibonacciQueue.cs b/src/QuikGraph/Collections/FibonacciQueue.cs index b0842e950..0a5fd93a5 100644 --- a/src/QuikGraph/Collections/FibonacciQueue.cs +++ b/src/QuikGraph/Collections/FibonacciQueue.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -31,6 +31,7 @@ public sealed class FibonacciQueue : IPriorityQueue /// Initializes a new instance of the class. /// /// Function that compute the distance for a given vertex. + /// is . public FibonacciQueue([NotNull] Func distanceFunc) : this(0, null, distanceFunc, Comparer.Default.Compare) { @@ -42,6 +43,8 @@ public FibonacciQueue([NotNull] Func distanceFunc) /// Initial capacity. /// Set of vertices (null if is 0). /// Function that compute the distance for a given vertex. + /// is . + /// is negative. public FibonacciQueue( int capacity, [CanBeNull, ItemNotNull] IEnumerable values, @@ -57,6 +60,9 @@ public FibonacciQueue( /// Set of vertices (null if is 0). /// Function that compute the distance for a given vertex. /// Comparer of distances. + /// is . + /// is . + /// is negative. public FibonacciQueue( int capacity, [CanBeNull, ItemNotNull] IEnumerable values, @@ -92,6 +98,7 @@ public FibonacciQueue( /// Initializes a new instance of the class. /// /// Dictionary of vertices associates to their distance. + /// is . public FibonacciQueue( [NotNull] Dictionary values) : this(values, Comparer.Default.Compare) @@ -103,6 +110,8 @@ public FibonacciQueue( /// /// Dictionary of vertices associates to their distance. /// Comparer of distances. + /// is . + /// is . public FibonacciQueue( [NotNull] Dictionary values, [NotNull] Comparison distanceComparison) diff --git a/src/QuikGraph/Collections/ForestDisjointSet.cs b/src/QuikGraph/Collections/ForestDisjointSet.cs index af9aa9000..f9a7f5447 100644 --- a/src/QuikGraph/Collections/ForestDisjointSet.cs +++ b/src/QuikGraph/Collections/ForestDisjointSet.cs @@ -61,6 +61,7 @@ public ForestDisjointSet() /// Initializes a new instance of the class. /// /// Element capacity. + /// is negative or . public ForestDisjointSet(int capacity) { if (capacity < 0 || capacity >= int.MaxValue) @@ -132,7 +133,9 @@ private static Element FindNoCompression([NotNull] Element element) // Find root Element current = element; while (current.Parent != null) + { current = current.Parent; + } Debug.Assert(current != null); return current; diff --git a/src/QuikGraph/Collections/Queue.cs b/src/QuikGraph/Collections/Queue.cs index f0ba55d56..8c3a8fc8b 100644 --- a/src/QuikGraph/Collections/Queue.cs +++ b/src/QuikGraph/Collections/Queue.cs @@ -1,10 +1,10 @@ -#if SUPPORTS_SERIALIZATION +#if SUPPORTS_SERIALIZATION using System; #endif namespace QuikGraph.Collections { - /// + /// #if SUPPORTS_SERIALIZATION [Serializable] #endif diff --git a/src/QuikGraph/Collections/SoftHeap.cs b/src/QuikGraph/Collections/SoftHeap.cs index 86e72fb1c..436bffb31 100644 --- a/src/QuikGraph/Collections/SoftHeap.cs +++ b/src/QuikGraph/Collections/SoftHeap.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -105,6 +105,8 @@ private sealed class Head /// /// Indicates the maximum error rate to respect. /// Gives the maximum key value. + /// is . + /// is not in range ]0, 0.5]. public SoftHeap(double maximumErrorRate, [NotNull] TKey keyMaxValue) : this(maximumErrorRate, keyMaxValue, Comparer.Default.Compare) { @@ -116,6 +118,9 @@ public SoftHeap(double maximumErrorRate, [NotNull] TKey keyMaxValue) /// Indicates the maximum error rate to respect. /// Gives the maximum key value. /// Key comparer. + /// is . + /// is . + /// is not in range ]0, 0.5]. public SoftHeap(double maximumErrorRate, [NotNull] TKey keyMaxValue, [NotNull] Comparison comparison) { if (keyMaxValue == null) @@ -166,6 +171,8 @@ public SoftHeap(double maximumErrorRate, [NotNull] TKey keyMaxValue, [NotNull] C /// /// Key. /// Value to add. + /// is . + /// is superior to . public void Add([NotNull] TKey key, [CanBeNull] TValue value) { if (key == null) @@ -236,7 +243,9 @@ private void FixMinList([NotNull] Head head) while (head != _header) { if (KeyComparison(tmpMin.Queue.CKey, head.Queue.CKey) > 0) + { tmpMin = head; + } head.SuffixMin = tmpMin; head = head.Prev; @@ -298,7 +307,9 @@ private void SoftenHeap([NotNull] Node node) node.Next.ILTail.Next = node.IL; node.IL = node.Next.IL; if (node.ILTail == null) + { node.ILTail = node.Next.ILTail; + } node.CKey = node.Next.CKey; } } // End second shift @@ -327,7 +338,7 @@ private void UpdateChildAndNext([NotNull] Node node) /// Gets and removes the minimal pair. /// /// The minimal pair. - /// The heap is empty. + /// The heap is empty. public KeyValuePair RemoveMinimum() { if (Count == 0) @@ -376,7 +387,9 @@ public KeyValuePair RemoveMinimum() TValue value = head.Queue.IL.Value; head.Queue.IL = head.Queue.IL.Next; if (head.Queue.IL is null) + { head.Queue.ILTail = null; + } --Count; return new KeyValuePair(min, value); diff --git a/src/QuikGraph/Collections/VertexEdgeDictionary.cs b/src/QuikGraph/Collections/VertexEdgeDictionary.cs index aa19432c7..95f6d08e8 100644 --- a/src/QuikGraph/Collections/VertexEdgeDictionary.cs +++ b/src/QuikGraph/Collections/VertexEdgeDictionary.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE +#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE using System; #endif using System.Collections.Generic; @@ -33,17 +33,13 @@ public VertexEdgeDictionary() /// Initializes a new instance of the class. /// /// Dictionary capacity. + /// is negative. public VertexEdgeDictionary(int capacity) : base(capacity) { } #if SUPPORTS_SERIALIZATION - /// - /// Initializes a new instance of with serialized data. - /// - /// that contains serialized data. - /// that contains contextual information. private VertexEdgeDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Collections/VertexList.cs b/src/QuikGraph/Collections/VertexList.cs index cfe968829..11d964f89 100644 --- a/src/QuikGraph/Collections/VertexList.cs +++ b/src/QuikGraph/Collections/VertexList.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE +#if SUPPORTS_SERIALIZATION || SUPPORTS_CLONEABLE using System; #endif using System.Collections.Generic; @@ -29,12 +29,14 @@ public VertexList() /// Initializes a new instance of the class. /// /// List capacity. + /// is negative. public VertexList(int capacity) : base(capacity) { } /// + /// is . public VertexList([NotNull] VertexList other) : base(other) { diff --git a/src/QuikGraph/Compatibility/SortedSet.cs b/src/QuikGraph/Compatibility/SortedSet.cs index 382626db0..b05512436 100644 --- a/src/QuikGraph/Compatibility/SortedSet.cs +++ b/src/QuikGraph/Compatibility/SortedSet.cs @@ -100,6 +100,7 @@ public SortedSet([CanBeNull] IComparer comparer) /// with given . /// /// Initial elements to add. + /// is . public SortedSet([NotNull, ItemCanBeNull] IEnumerable collection) : this(collection, Comparer.Default) { @@ -112,6 +113,7 @@ public SortedSet([NotNull, ItemCanBeNull] IEnumerable collection) /// /// Initial elements to add. /// to use. + /// is . public SortedSet([NotNull, ItemCanBeNull] IEnumerable collection, [CanBeNull] IComparer comparer) : this(comparer) { @@ -199,12 +201,8 @@ public SortedSet([NotNull, ItemCanBeNull] IEnumerable collection, [CanBeNull] private SerializationInfo _serializationInfo; // A temporary variable which we need during deserialization. /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. - protected SortedSet(SerializationInfo info, StreamingContext context) { _serializationInfo = info; @@ -649,7 +647,11 @@ public void CopyTo(T[] array, int index) /// Copies the content of this to the given array. /// Starts at given and copies elements. /// - public void CopyTo(T[] array, int index, int count) + /// is . + /// is too small. + /// is negative. + /// is negative. + public void CopyTo([NotNull] T[] array, int index, int count) { if (array is null) throw new ArgumentNullException(nameof(array)); @@ -1005,7 +1007,7 @@ private static void Split4Node([NotNull] Node node) /// The caller object is important as uses the Comparator /// associated with THIS to check equality. /// - /// If is null. + /// is . public void UnionWith([NotNull, ItemCanBeNull] IEnumerable other) { if (other is null) @@ -1165,7 +1167,7 @@ private static Node ConstructRootFromSortedArray( /// The caller object is important as uses the Comparator /// associated with THIS to check equality. /// - /// If is null. + /// is . public void IntersectWith([NotNull, ItemCanBeNull] IEnumerable other) { if (other is null) @@ -1247,7 +1249,7 @@ private void IntersectWithEnumerable([NotNull, ItemCanBeNull] IEnumerable oth /// The caller object is important as uses the Comparator /// associated with THIS to check equality. /// - /// If is null. + /// is . public void ExceptWith([NotNull, ItemCanBeNull] IEnumerable other) { if (other is null) @@ -1288,6 +1290,7 @@ public void ExceptWith([NotNull, ItemCanBeNull] IEnumerable other) /// /// Checks whether this Tree has all elements in common with . /// + /// is . public bool SetEquals([NotNull, ItemCanBeNull] IEnumerable other) { if (other is null) @@ -1413,8 +1416,9 @@ private unsafe ElementCount CheckUniqueAndUnfoundElements(IEnumerable other, /// /// Removes elements matching the given . /// - /// - /// + /// Predicate to match to removed elements. + /// Number of removed elements. + /// is . public int RemoveWhere([NotNull] Predicate predicate) { if (predicate is null) @@ -1488,7 +1492,7 @@ public T Max [NotNull, ItemCanBeNull] public IEnumerable Reverse() { - Enumerator e = new Enumerator(this, true); + var e = new Enumerator(this, true); while (e.MoveNext()) { yield return e.Current; diff --git a/src/QuikGraph/Events/EdgeEventArgs.cs b/src/QuikGraph/Events/EdgeEventArgs.cs index e7df17b7a..9f80a5dea 100644 --- a/src/QuikGraph/Events/EdgeEventArgs.cs +++ b/src/QuikGraph/Events/EdgeEventArgs.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph @@ -18,6 +18,7 @@ public class EdgeEventArgs : EventArgs /// Initializes a new instance of the class. /// /// Concerned edge. + /// is . public EdgeEventArgs([NotNull] TEdge edge) { if (edge == null) diff --git a/src/QuikGraph/Events/UndirectedEdgeEventArgs.cs b/src/QuikGraph/Events/UndirectedEdgeEventArgs.cs index 96269c57a..726721a71 100644 --- a/src/QuikGraph/Events/UndirectedEdgeEventArgs.cs +++ b/src/QuikGraph/Events/UndirectedEdgeEventArgs.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_SERIALIZATION +#if SUPPORTS_SERIALIZATION using System; #endif using JetBrains.Annotations; @@ -21,6 +21,7 @@ public class UndirectedEdgeEventArgs : EdgeEventArgs /// The edge. /// Indicates if the edge should be reversed or not. + /// is . public UndirectedEdgeEventArgs([NotNull] TEdge edge, bool reversed) : base(edge) { diff --git a/src/QuikGraph/Events/VertexEventArgs.cs b/src/QuikGraph/Events/VertexEventArgs.cs index c68b1d1eb..b78bc0a6e 100644 --- a/src/QuikGraph/Events/VertexEventArgs.cs +++ b/src/QuikGraph/Events/VertexEventArgs.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph @@ -16,6 +16,7 @@ public class VertexEventArgs : EventArgs /// Initializes a new instance of the class. /// /// Concerned vertex. + /// is . public VertexEventArgs([NotNull] TVertex vertex) { if (vertex == null) diff --git a/src/QuikGraph/Exceptions/NegativeCapacityException.cs b/src/QuikGraph/Exceptions/NegativeCapacityException.cs index 6d6944279..b56c043ab 100644 --- a/src/QuikGraph/Exceptions/NegativeCapacityException.cs +++ b/src/QuikGraph/Exceptions/NegativeCapacityException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -32,11 +32,8 @@ public NegativeCapacityException([NotNull] string message, [CanBeNull] Exception #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected NegativeCapacityException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/NegativeCycleGraphException.cs b/src/QuikGraph/Exceptions/NegativeCycleGraphException.cs index f0b3d5a71..d4fc9c1ae 100644 --- a/src/QuikGraph/Exceptions/NegativeCycleGraphException.cs +++ b/src/QuikGraph/Exceptions/NegativeCycleGraphException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -32,11 +32,8 @@ public NegativeCycleGraphException([NotNull] string message, [CanBeNull] Excepti #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected NegativeCycleGraphException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/NegativeWeightException.cs b/src/QuikGraph/Exceptions/NegativeWeightException.cs index 2339ab44c..f346f4c63 100644 --- a/src/QuikGraph/Exceptions/NegativeWeightException.cs +++ b/src/QuikGraph/Exceptions/NegativeWeightException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -32,11 +32,8 @@ public NegativeWeightException([NotNull] string message, [CanBeNull] Exception i #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected NegativeWeightException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/NoPathFoundException.cs b/src/QuikGraph/Exceptions/NoPathFoundException.cs index 5c28d3a34..d1491accc 100644 --- a/src/QuikGraph/Exceptions/NoPathFoundException.cs +++ b/src/QuikGraph/Exceptions/NoPathFoundException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -32,11 +32,8 @@ public NoPathFoundException([NotNull] string message, [CanBeNull] Exception inne #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected NoPathFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/NonAcyclicGraphException.cs b/src/QuikGraph/Exceptions/NonAcyclicGraphException.cs index 51bc8aee2..69cb70a65 100644 --- a/src/QuikGraph/Exceptions/NonAcyclicGraphException.cs +++ b/src/QuikGraph/Exceptions/NonAcyclicGraphException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -32,11 +32,8 @@ public NonAcyclicGraphException([NotNull] string message, [CanBeNull] Exception #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected NonAcyclicGraphException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/NonStronglyConnectedGraphException.cs b/src/QuikGraph/Exceptions/NonStronglyConnectedGraphException.cs index e023f0403..930beb29d 100644 --- a/src/QuikGraph/Exceptions/NonStronglyConnectedGraphException.cs +++ b/src/QuikGraph/Exceptions/NonStronglyConnectedGraphException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -32,11 +32,8 @@ public NonStronglyConnectedGraphException([NotNull] string message, [CanBeNull] #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected NonStronglyConnectedGraphException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/ParallelEdgeNotAllowedException.cs b/src/QuikGraph/Exceptions/ParallelEdgeNotAllowedException.cs index 2c38ea4d0..c5ec4c6e7 100644 --- a/src/QuikGraph/Exceptions/ParallelEdgeNotAllowedException.cs +++ b/src/QuikGraph/Exceptions/ParallelEdgeNotAllowedException.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; @@ -32,11 +32,8 @@ public ParallelEdgeNotAllowedException([NotNull] string message, [CanBeNull] Exc #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected ParallelEdgeNotAllowedException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/QuikGraphException.cs b/src/QuikGraph/Exceptions/QuikGraphException.cs index 3e2764bb8..86bfb1b1e 100644 --- a/src/QuikGraph/Exceptions/QuikGraphException.cs +++ b/src/QuikGraph/Exceptions/QuikGraphException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -26,11 +26,8 @@ protected QuikGraphException([NotNull] string message, [CanBeNull] Exception inn #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected QuikGraphException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Exceptions/VertexNotFoundException.cs b/src/QuikGraph/Exceptions/VertexNotFoundException.cs index cb713d6db..2b11d16bc 100644 --- a/src/QuikGraph/Exceptions/VertexNotFoundException.cs +++ b/src/QuikGraph/Exceptions/VertexNotFoundException.cs @@ -1,4 +1,4 @@ -using System; +using System; #if SUPPORTS_SERIALIZATION using System.Runtime.Serialization; #endif @@ -32,11 +32,8 @@ public VertexNotFoundException([NotNull] string message, [CanBeNull] Exception i #if SUPPORTS_SERIALIZATION /// - /// Initializes a new instance of with serialized data. + /// Constructor used during runtime serialization. /// - /// that contains serialized data - /// concerning the thrown exception. - /// that contains contextual information. protected VertexNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { diff --git a/src/QuikGraph/Extensions/AlgorithmExtensions.cs b/src/QuikGraph/Extensions/AlgorithmExtensions.cs index fb5e2478c..33169f02d 100644 --- a/src/QuikGraph/Extensions/AlgorithmExtensions.cs +++ b/src/QuikGraph/Extensions/AlgorithmExtensions.cs @@ -34,6 +34,7 @@ public static class AlgorithmExtensions /// Value type. /// Dictionary on which getting the key access method. /// A function allowing key indexed access. + /// is . [Pure] [NotNull] public static Func GetIndexer([NotNull] IDictionary dictionary) @@ -61,6 +62,7 @@ public static Func GetIndexer([NotNull] IDictionary< /// Vertex type. /// The graph. /// A function that computes a vertex identity for the given . + /// is . [Pure] [NotNull] public static VertexIdentity GetVertexIdentity([NotNull] this IVertexSet graph) @@ -97,7 +99,9 @@ public static VertexIdentity GetVertexIdentity([NotNull] this return vertex => { if (!ids.TryGetValue(vertex, out string id)) + { ids[vertex] = id = ids.Count.ToString(); + } return id; }; } @@ -109,6 +113,7 @@ public static VertexIdentity GetVertexIdentity([NotNull] this /// Edge type. /// The graph. /// A function that computes an edge identity for the given . + /// is . [Pure] [NotNull] public static EdgeIdentity GetEdgeIdentity([NotNull] this IEdgeSet graph) @@ -122,7 +127,9 @@ public static EdgeIdentity GetEdgeIdentity([NotN return edge => { if (!ids.TryGetValue(edge, out string id)) + { ids[edge] = id = ids.Count.ToString(); + } return id; }; } @@ -139,7 +146,9 @@ private static TryFunc> RunDirectedRootedAlgorithm(); using (predecessorRecorder.Attach(algorithm)) + { algorithm.Compute(source); + } IDictionary predecessors = predecessorRecorder.VerticesPredecessors; return (TVertex vertex, out IEnumerable edges) => predecessors.TryGetPath(vertex, out edges); @@ -155,6 +164,9 @@ private static TryFunc> RunDirectedRootedAlgorithmThe graph to visit. /// Starting vertex. /// A function that allow to get edges connected to a given vertex. + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> TreeBreadthFirstSearch( @@ -178,6 +190,9 @@ public static TryFunc> TreeBreadthFirstSearchThe graph to visit. /// Starting vertex. /// A function that allow to get edges connected to a given vertex. + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> TreeDepthFirstSearch( @@ -202,6 +217,9 @@ public static TryFunc> TreeDepthFirstSearchThe graph to visit. /// Starting vertex. /// A function that allow to get edges connected to a given vertex. + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> TreeCyclePoppingRandom( @@ -223,6 +241,11 @@ public static TryFunc> TreeCyclePoppingRandomStarting vertex. /// Markov edge chain. /// A function that allow to get edges connected to a given vertex. + /// is . + /// is . + /// is . + /// is not part of . + /// Something went wrong when running the algorithm. [Pure] [NotNull] public static TryFunc> TreeCyclePoppingRandom( @@ -250,6 +273,10 @@ public static TryFunc> TreeCyclePoppingRandomFunction that computes the weight for a given edge. /// Starting vertex. /// A function that allow to get paths starting from vertex. + /// is . + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> ShortestPathsDijkstra( @@ -275,6 +302,10 @@ public static TryFunc> ShortestPathsDijkstraFunction that computes the weight for a given edge. /// Starting vertex. /// A function that allow to get paths starting from vertex. + /// is . + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> ShortestPathsDijkstra( @@ -286,7 +317,9 @@ public static TryFunc> ShortestPathsDijkstra(graph, edgeWeights); var predecessorRecorder = new UndirectedVertexPredecessorRecorderObserver(); using (predecessorRecorder.Attach(algorithm)) + { algorithm.Compute(root); + } IDictionary predecessors = predecessorRecorder.VerticesPredecessors; return (TVertex vertex, out IEnumerable edges) => predecessors.TryGetPath(vertex, out edges); @@ -304,6 +337,11 @@ public static TryFunc> ShortestPathsDijkstraFunction that computes a cost for a given vertex. /// Starting vertex. /// A function that allow to get paths starting from vertex. + /// is . + /// is . + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> ShortestPathsAStar( @@ -331,6 +369,10 @@ public static TryFunc> ShortestPathsAStarStarting vertex. /// Indicates if a negative cycle has been found or not. /// A function that allow to get paths starting from vertex. + /// is . + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> ShortestPathsBellmanFord( @@ -350,7 +392,9 @@ public static TryFunc> ShortestPathsBellmanFord(graph, edgeWeights); var predecessorRecorder = new VertexPredecessorRecorderObserver(); using (predecessorRecorder.Attach(algorithm)) + { algorithm.Compute(root); + } hasNegativeCycle = algorithm.FoundNegativeCycle; @@ -369,6 +413,10 @@ public static TryFunc> ShortestPathsBellmanFordFunction that computes the weight for a given edge. /// Starting vertex. /// A function that allow to get paths starting from vertex. + /// is . + /// is . + /// is . + /// is not part of . [Pure] [NotNull] public static TryFunc> ShortestPathsDag( @@ -406,6 +454,12 @@ public static TryFunc> ShortestPathsDagTarget vertex. /// Maximal number of path to search. /// Enumeration of paths to go from vertex to . + /// is . + /// is . + /// is . + /// is . + /// or are not part of . + /// is lower or equal to 1. [Pure] [NotNull, ItemNotNull] public static IEnumerable> RankedShortestPathHoffmanPavley( @@ -434,6 +488,7 @@ public static IEnumerable> RankedShortestPathHoffmanPavleyEdge type. /// Graph to visit. /// Sink vertices. + /// is . [Pure] [NotNull, ItemNotNull] public static IEnumerable Sinks( @@ -452,6 +507,7 @@ public static IEnumerable Sinks( /// Edge type. /// Graph to visit. /// Root vertices. + /// is . [Pure] [NotNull, ItemNotNull] public static IEnumerable Roots( @@ -477,6 +533,7 @@ public static IEnumerable Roots( /// Edge type. /// Graph to visit. /// Root vertices. + /// is . [Pure] [NotNull, ItemNotNull] public static IEnumerable Roots( @@ -495,6 +552,7 @@ public static IEnumerable Roots( /// Edge type. /// Graph to visit. /// Root vertices. + /// is . [Pure] [NotNull, ItemNotNull] public static IEnumerable IsolatedVertices( @@ -515,6 +573,7 @@ public static IEnumerable IsolatedVertices( /// Edge type. /// Graph to visit. /// Sorted vertices (topological sort). + /// is . /// If the input graph has a cycle. [Pure] [NotNull, ItemNotNull] @@ -537,6 +596,7 @@ public static IEnumerable TopologicalSort( /// Edge type. /// Graph to visit. /// Sorted vertices (topological sort). + /// is . /// If the input graph has a cycle. [Pure] [NotNull, ItemNotNull] @@ -559,6 +619,7 @@ public static IEnumerable TopologicalSort( /// Edge type. /// Graph to visit. /// Sorted vertices (topological sort). + /// is . /// If the input graph has a cycle. [Pure] [NotNull, ItemNotNull] @@ -581,6 +642,7 @@ public static IEnumerable SourceFirstTopologicalSort( /// Edge type. /// Graph to visit. /// Sorted vertices (topological sort). + /// is . /// If the input graph has a cycle. [Pure] [NotNull, ItemNotNull] @@ -604,6 +666,7 @@ public static IEnumerable SourceFirstTopologicalSort( /// Edge type. /// Graph to visit. /// Sorted vertices (topological sort). + /// is . /// If the input graph has a cycle. [Pure] public static IEnumerable SourceFirstBidirectionalTopologicalSort( @@ -621,6 +684,7 @@ public static IEnumerable SourceFirstBidirectionalTopologicalSortGraph to visit. /// Topological sort direction. /// Sorted vertices (topological sort). + /// is . /// If the input graph has a cycle. [Pure] [NotNull, ItemNotNull] @@ -649,7 +713,8 @@ public static IEnumerable SourceFirstBidirectionalTopologicalSortGraph to visit. /// Found components. /// Number of component found. - [Pure] + /// is . + /// is . public static int ConnectedComponents( [NotNull] this IUndirectedGraph graph, [NotNull] IDictionary components) @@ -669,7 +734,9 @@ public static int ConnectedComponents( /// Edge type. /// Graph to visit. /// A function retrieve components of the . - /// A of the used algorithm. + /// A of the used algorithm. + /// is . + [Pure] [NotNull] public static IDisposable IncrementalConnectedComponents( [NotNull] this IMutableVertexAndEdgeSet graph, @@ -690,7 +757,8 @@ public static IDisposable IncrementalConnectedComponents( /// Graph to visit. /// Found components. /// Number of component found. - [Pure] + /// is . + /// is . public static int StronglyConnectedComponents( [NotNull] this IVertexListGraph graph, [NotNull] IDictionary components) @@ -709,7 +777,8 @@ public static int StronglyConnectedComponents( /// Graph to visit. /// Found components. /// Number of component found. - [Pure] + /// is . + /// is . public static int WeaklyConnectedComponents( [NotNull] this IVertexListGraph graph, [NotNull] IDictionary components) @@ -728,6 +797,7 @@ public static int WeaklyConnectedComponents( /// Graph type. /// Graph to visit. /// The condensed graph. + /// is . [Pure] [NotNull] public static IMutableBidirectionalGraph> CondensateStronglyConnected( @@ -751,6 +821,7 @@ public static IMutableBidirectionalGraphGraph type. /// Graph to visit. /// The condensed graph. + /// is . [Pure] [NotNull] public static IMutableBidirectionalGraph> CondensateWeaklyConnected( @@ -774,6 +845,8 @@ public static IMutableBidirectionalGraphGraph to visit. /// Vertex predicate used to filter the vertices to put in the condensed graph. /// The condensed graph. + /// is . + /// is . [Pure] [NotNull] public static IMutableBidirectionalGraph> CondensateEdges( @@ -797,6 +870,7 @@ public static IMutableBidirectionalGraph> Co /// /// Graph to visit. /// Enumerable of odd vertices. + /// is . [Pure] [NotNull, ItemNotNull] public static IEnumerable OddVertices( @@ -808,7 +882,9 @@ public static IEnumerable OddVertices( var counts = new Dictionary(graph.VertexCount); foreach (TVertex vertex in graph.Vertices) + { counts.Add(vertex, 0); + } foreach (TEdge edge in graph.Edges) { @@ -832,6 +908,7 @@ public static IEnumerable OddVertices( /// Edge type. /// Graph to visit. /// True if the graph contains a cycle, false otherwise. + /// is . [Pure] public static bool IsDirectedAcyclicGraph( [NotNull] this IVertexListGraph graph) @@ -881,6 +958,9 @@ private void DfsBackEdge([NotNull] TEdge edge) /// Costs map. /// Target vertex. /// The predecessors cost. + /// is . + /// is . + /// is . [Pure] public static double ComputePredecessorCost( [NotNull] IDictionary predecessors, @@ -913,6 +993,7 @@ public static double ComputePredecessorCost( /// Edge type. /// Graph to visit. /// Found disjoint sets. + /// is . [Pure] [NotNull] public static IDisjointSet ComputeDisjointSet( @@ -924,9 +1005,14 @@ public static IDisjointSet ComputeDisjointSet( var sets = new ForestDisjointSet(graph.VertexCount); foreach (TVertex vertex in graph.Vertices) + { sets.MakeSet(vertex); + } + foreach (TEdge edge in graph.Edges) + { sets.Union(edge.Source, edge.Target); + } return sets; } @@ -940,6 +1026,8 @@ public static IDisjointSet ComputeDisjointSet( /// Graph to visit. /// Function that computes the weight for a given edge. /// Edges part of the minimum spanning tree. + /// is . + /// is . [Pure] [NotNull, ItemNotNull] public static IEnumerable MinimumSpanningTreePrim( @@ -959,7 +1047,9 @@ public static IEnumerable MinimumSpanningTreePrim( var dijkstra = new UndirectedDijkstraShortestPathAlgorithm(graph, edgeWeights, distanceRelaxer); var edgeRecorder = new UndirectedVertexPredecessorRecorderObserver(); using (edgeRecorder.Attach(dijkstra)) + { dijkstra.Compute(); + } return edgeRecorder.VerticesPredecessors.Values; } @@ -972,6 +1062,8 @@ public static IEnumerable MinimumSpanningTreePrim( /// Graph to visit. /// Function that computes the weight for a given edge. /// Edges part of the minimum spanning tree. + /// is . + /// is . [Pure] [NotNull, ItemNotNull] public static IEnumerable MinimumSpanningTreeKruskal( @@ -990,7 +1082,9 @@ public static IEnumerable MinimumSpanningTreeKruskal( var kruskal = new KruskalMinimumSpanningTreeAlgorithm(graph, edgeWeights); var edgeRecorder = new EdgeRecorderObserver(); using (edgeRecorder.Attach(kruskal)) + { kruskal.Compute(); + } return edgeRecorder.Edges; } @@ -1011,6 +1105,10 @@ public static IEnumerable MinimumSpanningTreeKruskal( /// Starting vertex. /// Vertices pairs. /// A function that allow to get least common ancestor for a pair of vertices. + /// is . + /// is . + /// is . + /// At least one of vertices is not part of . [Pure] [NotNull] public static TryFunc, TVertex> OfflineLeastCommonAncestor( @@ -1050,6 +1148,13 @@ public static TryFunc, TVertex> OfflineLeastCommonAncest /// Edge factory method. /// Algorithm that is in of charge of augmenting the graph (creating missing reversed edges). /// The maximum flow. + /// is . + /// is . + /// is . + /// is . + /// is . + /// is . + /// and are the same vertex. public static double MaximumFlow( [NotNull] this IMutableVertexAndEdgeListGraph graph, [NotNull] Func edgeCapacities, @@ -1082,6 +1187,7 @@ public static double MaximumFlow( /// Edge type. /// Graph to compute the reduction. /// Transitive graph reduction. + /// is . [Pure] [NotNull] public static BidirectionalGraph ComputeTransitiveReduction( @@ -1099,16 +1205,18 @@ public static BidirectionalGraph ComputeTransitiveReductionVertex type. /// Edge type. /// Graph to compute the closure. - /// Function that create an edge between the 2 given vertices. + /// Function that create an edge between the 2 given vertices. /// Transitive graph closure. + /// is . + /// is . [Pure] [NotNull] public static BidirectionalGraph ComputeTransitiveClosure( [NotNull] this BidirectionalGraph graph, - [NotNull] Func createEdge) + [NotNull] Func edgeFactory) where TEdge : IEdge { - var algorithm = new TransitiveClosureAlgorithm(graph, createEdge); + var algorithm = new TransitiveClosureAlgorithm(graph, edgeFactory); algorithm.Compute(); return algorithm.TransitiveClosure; } @@ -1122,6 +1230,10 @@ public static BidirectionalGraph ComputeTransitiveClosureDelegate to clone a vertex. /// Delegate to clone an edge. /// Cloned graph. + /// is . + /// is or creates vertex. + /// is or creates edge. + /// is . public static void Clone( [NotNull] this IVertexAndEdgeListGraph graph, [NotNull, InstantHandle] Func vertexCloner, diff --git a/src/QuikGraph/Extensions/EdgeExtensions.cs b/src/QuikGraph/Extensions/EdgeExtensions.cs index 786a82373..97d09fbcd 100644 --- a/src/QuikGraph/Extensions/EdgeExtensions.cs +++ b/src/QuikGraph/Extensions/EdgeExtensions.cs @@ -20,6 +20,7 @@ public static class EdgeExtensions /// Vertex type. /// Edge to check. /// True if edge is a self one, false otherwise. + /// is . [Pure] public static bool IsSelfEdge([NotNull] this IEdge edge) { @@ -36,6 +37,8 @@ public static bool IsSelfEdge([NotNull] this IEdge edge) /// The edge. /// The source or target vertex of the . /// The other edge vertex. + /// is . + /// is . [Pure] [NotNull] public static TVertex GetOtherVertex([NotNull] this IEdge edge, [NotNull] TVertex vertex) @@ -56,6 +59,8 @@ public static TVertex GetOtherVertex([NotNull] this IEdge edge /// The edge. /// Source or target vertex. /// True if the is adjacent to this , false otherwise. + /// is . + /// is . [Pure] public static bool IsAdjacent([NotNull] this IEdge edge, [NotNull] TVertex vertex) { @@ -75,6 +80,7 @@ public static bool IsAdjacent([NotNull] this IEdge edge, [NotN /// Edge type. /// Sequence of edges. /// True if the set makes a complete path, false otherwise. + /// is . [Pure] public static bool IsPath([NotNull, ItemNotNull] this IEnumerable path) where TEdge : IEdge @@ -83,7 +89,7 @@ public static bool IsPath([NotNull, ItemNotNull] this IEnumerabl throw new ArgumentNullException(nameof(path)); bool first = true; - TVertex lastTarget = default(TVertex); + var lastTarget = default(TVertex); foreach (TEdge edge in path) { if (first) @@ -110,6 +116,7 @@ public static bool IsPath([NotNull, ItemNotNull] this IEnumerabl /// Edge type. /// Sequence of edges. /// True if the set makes a cycle, false otherwise. + /// is . [Pure] public static bool HasCycles([NotNull, ItemNotNull] this IEnumerable path) where TEdge : IEdge @@ -147,6 +154,7 @@ public static bool HasCycles([NotNull, ItemNotNull] this IEnumer /// Edge type. /// Path of edges. /// True if the path makes a cycle, false otherwise. + /// is . [Pure] public static bool IsPathWithoutCycles([NotNull, ItemNotNull] this IEnumerable path) where TEdge : IEdge @@ -156,7 +164,7 @@ public static bool IsPathWithoutCycles([NotNull, ItemNotNull] th var vertices = new Dictionary(); bool first = true; - TVertex lastTarget = default(TVertex); + var lastTarget = default(TVertex); foreach (TEdge edge in path) { if (first) @@ -189,6 +197,7 @@ public static bool IsPathWithoutCycles([NotNull, ItemNotNull] th /// Vertex type. /// The edge. /// A . + /// is . [Pure] public static SEquatableEdge ToVertexPair([NotNull] this IEdge edge) { @@ -206,6 +215,9 @@ public static SEquatableEdge ToVertexPair([NotNull] this IEdge /// Root vertex. /// Ending vertex. /// True if the is a predecessor of the . + /// is . + /// is . + /// is . [Pure] public static bool IsPredecessor( [NotNull] this IDictionary predecessors, @@ -246,6 +258,8 @@ public static bool IsPredecessor( /// Path ending vertex. /// Path to the ending vertex. /// True if a path was found, false otherwise. + /// is . + /// is . [Pure] [ContractAnnotation("=> true, path:notnull;=> false, path:null")] public static bool TryGetPath( @@ -315,6 +329,9 @@ public static EdgeEqualityComparer GetUndirectedVertexEqualityTarget vertex. /// True if both and /// match edge vertices, false otherwise. + /// is . + /// is . + /// is . [Pure] public static bool UndirectedVertexEquality( [NotNull] this IEdge edge, @@ -357,6 +374,9 @@ internal static bool UndirectedVertexEqualityInternal( /// Target vertex. /// True if both and /// match edge vertices, false otherwise. + /// is . + /// is . + /// is . [Pure] public static bool SortedVertexEquality( [NotNull] this IEdge edge, @@ -394,6 +414,7 @@ internal static bool SortedVertexEqualityInternal( /// Edge type. /// Edges to reversed. /// Reversed edges. + /// is . [Pure] [NotNull] public static IEnumerable> ReverseEdges( diff --git a/src/QuikGraph/Extensions/GraphExtensions.cs b/src/QuikGraph/Extensions/GraphExtensions.cs index 9928d0c91..8f8a50096 100644 --- a/src/QuikGraph/Extensions/GraphExtensions.cs +++ b/src/QuikGraph/Extensions/GraphExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; using static QuikGraph.QuikGraphHelpers; @@ -19,6 +19,7 @@ public static class GraphExtensions /// Edge type. /// Getter of out-edges. /// A corresponding . + /// is . [Pure] [NotNull] public static DelegateIncidenceGraph ToDelegateIncidenceGraph( @@ -35,6 +36,7 @@ public static DelegateIncidenceGraph ToDelegateIncidenceGraphEdge type. /// Getter of out-edges. /// A corresponding . + /// is . [Pure] [NotNull] public static DelegateIncidenceGraph ToDelegateIncidenceGraph( @@ -54,6 +56,7 @@ public static DelegateIncidenceGraph ToDelegateIncidenceGraphType of the enumerable of out-edges. /// Vertices and edges mapping. /// A corresponding . + /// is . [Pure] [NotNull] public static DelegateVertexAndEdgeListGraph ToDelegateVertexAndEdgeListGraph( @@ -73,6 +76,8 @@ public static DelegateVertexAndEdgeListGraph ToDelegateVertexAnd /// Vertices and edges mapping. /// Converter of vertex/edge mapping to enumerable of edges. /// A corresponding . + /// is . + /// is . [Pure] [NotNull] public static DelegateVertexAndEdgeListGraph ToDelegateVertexAndEdgeListGraph( @@ -113,6 +118,8 @@ public static DelegateVertexAndEdgeListGraph ToDelegateVertexAnd /// Enumerable of vertices. /// Getter of out-edges. /// A corresponding . + /// is . + /// is . [Pure] [NotNull] public static DelegateVertexAndEdgeListGraph ToDelegateVertexAndEdgeListGraph( @@ -132,6 +139,8 @@ public static DelegateVertexAndEdgeListGraph ToDelegateVertexAnd /// Enumerable of vertices. /// Getter of out-edges. /// A corresponding . + /// is . + /// is . [Pure] [NotNull] public static DelegateVertexAndEdgeListGraph ToDelegateVertexAndEdgeListGraph( @@ -153,6 +162,8 @@ public static DelegateVertexAndEdgeListGraph ToDelegateVertexAnd /// Getter of out-edges. /// Getter of in-edges. /// A corresponding . + /// is . + /// is . [Pure] [NotNull] public static DelegateBidirectionalIncidenceGraph ToDelegateBidirectionalIncidenceGraph( @@ -172,6 +183,8 @@ public static DelegateBidirectionalIncidenceGraph ToDelegateBidi /// Enumerable of vertices. /// Getter of adjacent edges. /// A corresponding . + /// is . + /// is . [Pure] [NotNull] public static DelegateUndirectedGraph ToDelegateUndirectedGraph( @@ -191,6 +204,8 @@ public static DelegateUndirectedGraph ToDelegateUndirectedGraph< /// Enumerable of vertices. /// Getter of adjacent edges. /// A corresponding . + /// is . + /// is . [Pure] [NotNull] public static DelegateUndirectedGraph ToDelegateUndirectedGraph( @@ -216,6 +231,11 @@ public static DelegateUndirectedGraph ToDelegateUndirectedGraph< /// The first items of each column represents the number of vertices following. /// /// A corresponding . + /// + /// , [0] or [1] is . + /// + /// length is different from 2. + /// [0] length is different from [1] length. [Pure] [NotNull] public static AdjacencyGraph> ToAdjacencyGraph( @@ -237,7 +257,9 @@ public static AdjacencyGraph> ToAdjacencyGraph< int n = sources.Length; var edgePairs = new List>(n); for (int i = 0; i < n; ++i) + { edgePairs.Add(new SEquatableEdge(sources[i], targets[i])); + } return ToAdjacencyGraph(edgePairs); } @@ -250,6 +272,9 @@ public static AdjacencyGraph> ToAdjacencyGraph< /// Set of edges to convert. /// Indicates if parallel edges are allowed. /// A corresponding . + /// + /// is or at least one of them is . + /// [Pure] [NotNull] public static AdjacencyGraph ToAdjacencyGraph( @@ -268,6 +293,9 @@ public static AdjacencyGraph ToAdjacencyGraph( /// Vertex type. /// Set of vertex pairs to convert. /// A corresponding . + /// + /// is or at least one of vertex is . + /// [Pure] [NotNull] public static AdjacencyGraph> ToAdjacencyGraph( @@ -291,6 +319,12 @@ public static AdjacencyGraph> ToAdjacencyGraph< /// The out edges factory. /// Indicates if parallel edges are allowed. /// A corresponding . + /// + /// is or at least one of them is . + /// + /// + /// is or creates edge. + /// [Pure] [NotNull] public static AdjacencyGraph ToAdjacencyGraph( @@ -306,7 +340,9 @@ public static AdjacencyGraph ToAdjacencyGraph( graph.AddVertexRange(vertices); foreach (TVertex vertex in graph.Vertices) + { graph.AddEdgeRange(outEdgesFactory(vertex)); + } return graph; } @@ -318,6 +354,7 @@ public static AdjacencyGraph ToAdjacencyGraph( /// Edge type. /// Graph to convert. /// A corresponding . + /// is . [Pure] [NotNull] public static ArrayAdjacencyGraph ToArrayAdjacencyGraph( @@ -335,6 +372,7 @@ public static ArrayAdjacencyGraph ToArrayAdjacencyGraphEdge type. /// Graph to convert. /// A corresponding . + /// is . [Pure] [NotNull] public static IBidirectionalGraph ToBidirectionalGraph( @@ -358,6 +396,9 @@ public static IBidirectionalGraph ToBidirectionalGraphSet of edges to convert. /// Indicates if parallel edges are allowed. /// A corresponding . + /// + /// is or at least one of them is . + /// [Pure] [NotNull] public static BidirectionalGraph ToBidirectionalGraph( @@ -376,6 +417,9 @@ public static BidirectionalGraph ToBidirectionalGraphVertex type. /// Set of vertex pairs to convert. /// A corresponding . + /// + /// is or at least one of vertex is . + /// [Pure] [NotNull] public static BidirectionalGraph> ToBidirectionalGraph( @@ -399,6 +443,12 @@ public static BidirectionalGraph> ToBidirection /// The out edges factory. /// Indicates if parallel edges are allowed. /// A corresponding . + /// + /// is or at least one of them is . + /// + /// + /// is or creates edge. + /// [Pure] [NotNull] public static BidirectionalGraph ToBidirectionalGraph( @@ -414,7 +464,9 @@ public static BidirectionalGraph ToBidirectionalGraph ToBidirectionalGraph /// Graph to convert. /// A corresponding . + /// is . [NotNull] public static BidirectionalGraph ToBidirectionalGraph( [NotNull] this IUndirectedGraph graph) @@ -447,6 +500,7 @@ public static BidirectionalGraph ToBidirectionalGraphEdge type. /// Graph to convert. /// A corresponding . + /// is . [Pure] [NotNull] public static ArrayBidirectionalGraph ToArrayBidirectionalGraph( @@ -464,6 +518,9 @@ public static ArrayBidirectionalGraph ToArrayBidirectionalGraph< /// Set of edges to convert. /// Indicates if parallel edges are allowed. /// A corresponding . + /// + /// is or at least one of them is . + /// [Pure] [NotNull] public static UndirectedGraph ToUndirectedGraph( @@ -482,6 +539,7 @@ public static UndirectedGraph ToUndirectedGraph( /// Vertex type. /// Set of vertex pairs to convert. /// A corresponding . + /// is . [Pure] [NotNull] public static UndirectedGraph> ToUndirectedGraph( @@ -502,6 +560,7 @@ public static UndirectedGraph> ToUndirectedGrap /// Edge type. /// Graph to convert. /// A corresponding . + /// is . [Pure] [NotNull] public static ArrayUndirectedGraph ToArrayUndirectedGraph( @@ -512,19 +571,20 @@ public static ArrayUndirectedGraph ToArrayUndirectedGraph - /// Creates an immutable compressed row graph representation of the . + /// Creates an immutable compressed row graph representation of the . /// /// Vertex type. /// Edge type. - /// Graph to visit. + /// Graph to visit. /// A corresponding . + /// is . [Pure] [NotNull] public static CompressedSparseRowGraph ToCompressedRowGraph( - [NotNull] this IVertexAndEdgeListGraph visitedGraph) + [NotNull] this IVertexAndEdgeListGraph graph) where TEdge : IEdge { - return CompressedSparseRowGraph.FromGraph(visitedGraph); + return CompressedSparseRowGraph.FromGraph(graph); } #endregion diff --git a/src/QuikGraph/Helpers/CryptoRandom.cs b/src/QuikGraph/Helpers/CryptoRandom.cs index 1cc2f2da1..62274fa8e 100644 --- a/src/QuikGraph/Helpers/CryptoRandom.cs +++ b/src/QuikGraph/Helpers/CryptoRandom.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_CRYPTO_RANDOM +#if SUPPORTS_CRYPTO_RANDOM using System; using System.Security.Cryptography; using JetBrains.Annotations; @@ -10,7 +10,7 @@ namespace QuikGraph.Utils /// /// /// Note that because of security issue the seed is unused in this random number generator. - /// Note also that it is slower than classic but on purpose. + /// Note also that it is slower than classic but on purpose. /// public class CryptoRandom : Random { @@ -30,7 +30,7 @@ public CryptoRandom() /// /// Initializes a new instance of the class. /// - /// Seed is ignored, just to keep same API as . + /// Seed is ignored, just to keep same API as . // ReSharper disable once UnusedParameter.Local public CryptoRandom(int ignoredSeed) { diff --git a/src/QuikGraph/Helpers/GraphEqualityHelpers.cs b/src/QuikGraph/Helpers/GraphEqualityHelpers.cs index 5bfa02c8e..3323005b8 100644 --- a/src/QuikGraph/Helpers/GraphEqualityHelpers.cs +++ b/src/QuikGraph/Helpers/GraphEqualityHelpers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -22,6 +22,8 @@ public static class EquateGraphs /// Vertex equality comparer. /// Edge equality comparer. /// True if both graphs are equal, false otherwise. + /// is . + /// is . [Pure] public static bool Equate( [CanBeNull] IEdgeListGraph g, diff --git a/src/QuikGraph/Interfaces/Algorithms/IDistancesCollection.cs b/src/QuikGraph/Interfaces/Algorithms/IDistancesCollection.cs index d18a53a40..6e86d1d92 100644 --- a/src/QuikGraph/Interfaces/Algorithms/IDistancesCollection.cs +++ b/src/QuikGraph/Interfaces/Algorithms/IDistancesCollection.cs @@ -15,22 +15,24 @@ public interface IDistancesCollection /// The vertex. /// Associated distance. /// True if the distance was found, false otherwise. + /// is . [Pure] bool TryGetDistance([NotNull] TVertex vertex, out double distance); /// /// Gets the distance associated to the given . - /// Will throw a if the vertex does not exist in the collection. /// /// The vertex to get the distance for. /// The distance associated with the vertex. + /// is . + /// has no recorded distance. [Pure] double GetDistance([NotNull] TVertex vertex); /// /// Gets the distances for all vertices currently known. /// - /// The for the known vertices. + /// The for the known vertices. [Pure] [NotNull] IEnumerable> GetDistances(); diff --git a/src/QuikGraph/Interfaces/Algorithms/IVertexColorizerAlgorithm.cs b/src/QuikGraph/Interfaces/Algorithms/IVertexColorizerAlgorithm.cs index a7eeba8e9..4391103c3 100644 --- a/src/QuikGraph/Interfaces/Algorithms/IVertexColorizerAlgorithm.cs +++ b/src/QuikGraph/Interfaces/Algorithms/IVertexColorizerAlgorithm.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph.Algorithms { @@ -13,6 +13,8 @@ public interface IVertexColorizerAlgorithm /// /// The vertex. /// The vertex . + /// is . + /// has no associated color. [Pure] GraphColor GetVertexColor([NotNull] TVertex vertex); } diff --git a/src/QuikGraph/Interfaces/Algorithms/Observers/IObserver.cs b/src/QuikGraph/Interfaces/Algorithms/Observers/IObserver.cs index d1f47f635..30843cce4 100644 --- a/src/QuikGraph/Interfaces/Algorithms/Observers/IObserver.cs +++ b/src/QuikGraph/Interfaces/Algorithms/Observers/IObserver.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Algorithms.Observers @@ -11,11 +11,12 @@ namespace QuikGraph.Algorithms.Observers public interface IObserver { /// - /// Attaches to the algorithm events and returns a + /// Attaches to the algorithm events and returns a /// object that can be used to detach from the events. /// /// Algorithm to observe. - /// allowing to detach from registered events. + /// allowing to detach from registered events. + /// is . [NotNull] IDisposable Attach([NotNull] TAlgorithm algorithm); } diff --git a/src/QuikGraph/Interfaces/Collections/IDisjointSet.cs b/src/QuikGraph/Interfaces/Collections/IDisjointSet.cs index 5ec560b0f..1ddae24bf 100644 --- a/src/QuikGraph/Interfaces/Collections/IDisjointSet.cs +++ b/src/QuikGraph/Interfaces/Collections/IDisjointSet.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph.Collections { @@ -22,6 +22,7 @@ public interface IDisjointSet /// Creates a new set for the . /// /// The value. + /// is . void MakeSet([NotNull] T value); /// @@ -29,6 +30,7 @@ public interface IDisjointSet /// /// Value to search. /// Root value of the set. + /// is . [Pure] [NotNull] T FindSet([NotNull] T value); @@ -39,6 +41,8 @@ public interface IDisjointSet /// Left value. /// Right value. /// True if both values are in the same set, false otherwise. + /// is . + /// is . [Pure] bool AreInSameSet([NotNull] T left, [NotNull] T right); @@ -49,6 +53,8 @@ public interface IDisjointSet /// Right value. /// True if and were unioned, /// false if they already belong to the same set. + /// is . + /// is . bool Union([NotNull] T left, [NotNull] T right); /// @@ -56,6 +62,7 @@ public interface IDisjointSet /// /// The value. /// True if the value is already in the set, false otherwise. + /// is . [Pure] bool Contains([NotNull] T value); } diff --git a/src/QuikGraph/Interfaces/Collections/IQueue.cs b/src/QuikGraph/Interfaces/Collections/IQueue.cs index 9ed868e8d..1199f573c 100644 --- a/src/QuikGraph/Interfaces/Collections/IQueue.cs +++ b/src/QuikGraph/Interfaces/Collections/IQueue.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph.Collections { @@ -31,12 +31,14 @@ public interface IQueue /// Dequeues an element from the queue. /// /// Removed element. + /// Queue is empty. T Dequeue(); /// /// Returns the element at the beginning of the queue. /// /// The top queue element. + /// Queue is empty. [Pure] T Peek(); diff --git a/src/QuikGraph/Interfaces/Edges/ICloneableEdge.cs b/src/QuikGraph/Interfaces/Edges/ICloneableEdge.cs index e0b1babbf..8173fd483 100644 --- a/src/QuikGraph/Interfaces/Edges/ICloneableEdge.cs +++ b/src/QuikGraph/Interfaces/Edges/ICloneableEdge.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph { @@ -17,6 +17,8 @@ public interface ICloneableEdge : IEdge /// The source vertex of the new edge. /// The target vertex of the new edge. /// A clone of the edge with new source and target vertices. + /// is . + /// is . [Pure] [NotNull] TEdge Clone([NotNull] TVertex source, [NotNull] TVertex target); diff --git a/src/QuikGraph/Interfaces/Edges/IEdgeSet.cs b/src/QuikGraph/Interfaces/Edges/IEdgeSet.cs index 9baa860ab..08f9edde9 100644 --- a/src/QuikGraph/Interfaces/Edges/IEdgeSet.cs +++ b/src/QuikGraph/Interfaces/Edges/IEdgeSet.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -33,6 +33,7 @@ public interface IEdgeSet /// /// Edge to check. /// True if the specified is contained in this set, false otherwise. + /// is . [Pure] bool ContainsEdge([NotNull] TEdge edge); } diff --git a/src/QuikGraph/Interfaces/Graphs/IBidirectionalIncidenceGraph.cs b/src/QuikGraph/Interfaces/Graphs/IBidirectionalIncidenceGraph.cs index 81feb0c28..43d071b25 100644 --- a/src/QuikGraph/Interfaces/Graphs/IBidirectionalIncidenceGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IBidirectionalIncidenceGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -18,6 +18,8 @@ public interface IBidirectionalIncidenceGraph : IIncidenceGraph< /// /// The vertex. /// True if has no in-edges, false otherwise. + /// is . + /// is not part of the graph. [Pure] bool IsInEdgesEmpty([NotNull] TVertex vertex); @@ -26,6 +28,8 @@ public interface IBidirectionalIncidenceGraph : IIncidenceGraph< /// /// The vertex. /// The number of in-edges pointing towards . + /// is . + /// is not part of the graph. [Pure] int InDegree([NotNull] TVertex vertex); @@ -34,6 +38,8 @@ public interface IBidirectionalIncidenceGraph : IIncidenceGraph< /// /// The vertex. /// The collection of in-edges of . + /// is . + /// is not part of the graph. [Pure] [NotNull, ItemNotNull] IEnumerable InEdges([NotNull] TVertex vertex); @@ -44,6 +50,7 @@ public interface IBidirectionalIncidenceGraph : IIncidenceGraph< /// The vertex. /// In-edges. /// True if was found or/and in-edges were found, false otherwise. + /// is . [Pure] [ContractAnnotation("=> true, edges:notnull;=> false, edges:null")] bool TryGetInEdges([NotNull] TVertex vertex, [ItemNotNull] out IEnumerable edges); @@ -54,6 +61,9 @@ public interface IBidirectionalIncidenceGraph : IIncidenceGraph< /// The vertex. /// The index. /// The in-edge at position . + /// is . + /// No vertex at . + /// is not part of the graph. [Pure] [NotNull] TEdge InEdge([NotNull] TVertex vertex, int index); @@ -64,6 +74,8 @@ public interface IBidirectionalIncidenceGraph : IIncidenceGraph< /// /// The vertex. /// The sum of OutDegree and InDegree of . + /// is . + /// is not part of the graph. [Pure] int Degree([NotNull] TVertex vertex); } diff --git a/src/QuikGraph/Interfaces/Graphs/IClusteredGraph.cs b/src/QuikGraph/Interfaces/Graphs/IClusteredGraph.cs index 62a34b8d3..4370a3612 100644 --- a/src/QuikGraph/Interfaces/Graphs/IClusteredGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IClusteredGraph.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using JetBrains.Annotations; namespace QuikGraph @@ -35,6 +35,7 @@ public interface IClusteredGraph /// Removes the given graph from this cluster. /// /// The graph. + /// is . void RemoveCluster([NotNull] IClusteredGraph graph); } } \ No newline at end of file diff --git a/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs b/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs index 6b0df3639..2893039c5 100644 --- a/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs +++ b/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -22,7 +22,8 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph /// The vertex. /// The parent vertex if there is one, otherwise null. - /// The given is the root of the graph. + /// is . + /// The given is the root of the graph. [Pure] [CanBeNull] TVertex GetParent([NotNull] TVertex vertex); @@ -32,7 +33,8 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph /// The vertex. /// The parent vertex edge. - /// The is the root of the graph. + /// is . + /// The given is the root of the graph. [Pure] [CanBeNull] TEdge GetParentEdge([NotNull] TVertex vertex); @@ -42,6 +44,7 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph /// The edge. /// True if the edge is a cross edge, false otherwise. + /// is . [Pure] bool IsCrossEdge([NotNull] TEdge edge); @@ -51,6 +54,7 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph /// The edge. /// True if it's a real edge, false otherwise. + /// is . [Pure] bool IsRealEdge([NotNull] TEdge edge); @@ -61,6 +65,8 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraphSource vertex. /// Target vertex. /// True if the is a predecessor of . + /// is . + /// is . [Pure] bool IsPredecessorOf([NotNull] TVertex source, [NotNull] TVertex target); @@ -70,8 +76,12 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraphSource vertex. /// Target vertex. /// The number of edge between and . - /// The is a predecessor of - /// or the other-way round. + /// is . + /// is . + /// + /// The is a predecessor of + /// or the other-way round. + /// [Pure] int InducedEdgeCount([NotNull] TVertex source, [NotNull] TVertex target); @@ -80,6 +90,7 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph /// The vertex. /// True if the is not a leaf, false otherwise. + /// is . [Pure] bool IsInnerNode([NotNull] TVertex vertex); @@ -88,6 +99,7 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph /// The vertex. /// Children edges. + /// is . [Pure] [NotNull, ItemNotNull] IEnumerable ChildrenEdges([NotNull] TVertex vertex); @@ -97,6 +109,7 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph /// The vertex. /// Children vertices. + /// is . [Pure] [NotNull, ItemNotNull] IEnumerable ChildrenVertices([NotNull] TVertex vertex); diff --git a/src/QuikGraph/Interfaces/Graphs/IImplicitGraph.cs b/src/QuikGraph/Interfaces/Graphs/IImplicitGraph.cs index 695fe6556..ea548fdb9 100644 --- a/src/QuikGraph/Interfaces/Graphs/IImplicitGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IImplicitGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -17,6 +17,8 @@ public interface IImplicitGraph : IGraph, IImpli /// /// The vertex. /// True if has no out-edges, false otherwise. + /// is . + /// is not part of the graph. [Pure] bool IsOutEdgesEmpty([NotNull] TVertex vertex); @@ -25,6 +27,8 @@ public interface IImplicitGraph : IGraph, IImpli /// /// The vertex. /// The count of out-edges of . + /// is . + /// is not part of the graph. [Pure] int OutDegree([NotNull] TVertex vertex); @@ -33,6 +37,8 @@ public interface IImplicitGraph : IGraph, IImpli /// /// The vertex. /// An enumeration of the out-edges of . + /// is . + /// is not part of the graph. [Pure] [NotNull, ItemNotNull] IEnumerable OutEdges([NotNull] TVertex vertex); @@ -43,6 +49,7 @@ public interface IImplicitGraph : IGraph, IImpli /// The vertex. /// Out-edges. /// True if was found or/and out-edges were found, false otherwise. + /// is . [Pure] [ContractAnnotation("=> true, edges:notnull;=> false, edges:null")] bool TryGetOutEdges([NotNull] TVertex vertex, [ItemNotNull] out IEnumerable edges); @@ -53,6 +60,9 @@ public interface IImplicitGraph : IGraph, IImpli /// The vertex. /// The index. /// The out-edge at position . + /// is . + /// No vertex at . + /// is not part of the graph. [Pure] [NotNull] TEdge OutEdge([NotNull] TVertex vertex, int index); diff --git a/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs b/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs index 913586cec..9478a489d 100644 --- a/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -23,6 +23,8 @@ public interface IImplicitUndirectedGraph : IImplicitVertexSet /// The vertex. /// Enumerable of adjacent edges. + /// is . + /// is not part of the graph. [Pure] [NotNull, ItemNotNull] IEnumerable AdjacentEdges([NotNull] TVertex vertex); @@ -32,6 +34,8 @@ public interface IImplicitUndirectedGraph : IImplicitVertexSet /// The vertex. /// Vertex adjacent degree. + /// is . + /// is not part of the graph. [Pure] int AdjacentDegree([NotNull] TVertex vertex); @@ -40,6 +44,8 @@ public interface IImplicitUndirectedGraph : IImplicitVertexSet /// The vertex. /// True if the vertex has at least one adjacent edge, false otherwise. + /// is . + /// is not part of the graph. [Pure] bool IsAdjacentEdgesEmpty([NotNull] TVertex vertex); @@ -49,6 +55,9 @@ public interface IImplicitUndirectedGraph : IImplicitVertexSetThe vertex. /// Index of the adjacent edge requested. /// The adjacent edge. + /// is . + /// No vertex at . + /// is not part of the graph. [Pure] [NotNull] TEdge AdjacentEdge([NotNull] TVertex vertex, int index); @@ -61,6 +70,8 @@ public interface IImplicitUndirectedGraph : IImplicitVertexSetTarget vertex. /// Edge found, otherwise null. /// True if an edge was found, false otherwise. + /// is . + /// is . [Pure] [ContractAnnotation("=> true, edge:notnull;=> false, edge:null")] bool TryGetEdge([NotNull] TVertex source, [NotNull] TVertex target, out TEdge edge); @@ -72,6 +83,8 @@ public interface IImplicitUndirectedGraph : IImplicitVertexSetSource vertex. /// Target vertex. /// True if an edge exists, false otherwise. + /// is . + /// is . [Pure] bool ContainsEdge([NotNull] TVertex source, [NotNull] TVertex target); } diff --git a/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs b/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs index 4f309b317..a977fbf07 100644 --- a/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -19,6 +19,8 @@ public interface IIncidenceGraph : IImplicitGraphSource vertex. /// Target vertex. /// True if an edge exists, false otherwise. + /// is . + /// is . [Pure] bool ContainsEdge([NotNull] TVertex source, [NotNull] TVertex target); @@ -30,6 +32,8 @@ public interface IIncidenceGraph : IImplicitGraphTarget vertex. /// Edge found, otherwise null. /// True if an edge was found, false otherwise. + /// is . + /// is . [Pure] [ContractAnnotation("=> true, edge:notnull;=> false, edge:null")] bool TryGetEdge([NotNull] TVertex source, [NotNull] TVertex target, out TEdge edge); @@ -42,6 +46,8 @@ public interface IIncidenceGraph : IImplicitGraphTarget vertex. /// Edges found, otherwise null. /// True if at least an edge was found, false otherwise. + /// is . + /// is . [Pure] [ContractAnnotation("=> true, edges:notnull;=> false, edges:null")] bool TryGetEdges([NotNull] TVertex source, [NotNull] TVertex target, [ItemNotNull] out IEnumerable edges); diff --git a/src/QuikGraph/Interfaces/Graphs/IMutableBidirectionalGraph.cs b/src/QuikGraph/Interfaces/Graphs/IMutableBidirectionalGraph.cs index 7527e021d..84b5a7c02 100644 --- a/src/QuikGraph/Interfaces/Graphs/IMutableBidirectionalGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IMutableBidirectionalGraph.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph { @@ -20,18 +20,22 @@ public interface IMutableBidirectionalGraph /// The vertex. /// Edge predicate. /// Number of edges removed. + /// is . + /// is . int RemoveInEdgeIf([NotNull] TVertex vertex, [NotNull, InstantHandle] EdgePredicate predicate); /// /// Clears in-edges of the given . /// /// The vertex. + /// is . void ClearInEdges([NotNull] TVertex vertex); /// /// Clears in-edges and out-edges of the given . /// /// The vertex. + /// is . void ClearEdges([NotNull] TVertex vertex); } } \ No newline at end of file diff --git a/src/QuikGraph/Interfaces/Graphs/IMutableEdgeListGraph.cs b/src/QuikGraph/Interfaces/Graphs/IMutableEdgeListGraph.cs index d9a7a4ab5..0d55afbdb 100644 --- a/src/QuikGraph/Interfaces/Graphs/IMutableEdgeListGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IMutableEdgeListGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -17,6 +17,7 @@ public interface IMutableEdgeListGraph : IMutableGraph /// An edge. /// True if the edge was added, false otherwise. + /// is . bool AddEdge([NotNull] TEdge edge); /// @@ -29,6 +30,9 @@ public interface IMutableEdgeListGraph : IMutableGraph /// Edges to add. /// The number of edges successfully added to this graph. + /// + /// is or at least one of them is . + /// int AddEdgeRange([NotNull, ItemNotNull] IEnumerable edges); /// @@ -36,6 +40,7 @@ public interface IMutableEdgeListGraph : IMutableGraph /// Edge to remove. /// True if the was successfully removed, false otherwise. + /// is . bool RemoveEdge([NotNull] TEdge edge); /// @@ -48,6 +53,7 @@ public interface IMutableEdgeListGraph : IMutableGraph /// Predicate to check if an edge should be removed. /// The number of edges removed. + /// is . int RemoveEdgeIf([NotNull, InstantHandle] EdgePredicate predicate); } } \ No newline at end of file diff --git a/src/QuikGraph/Interfaces/Graphs/IMutableIncidenceGraph.cs b/src/QuikGraph/Interfaces/Graphs/IMutableIncidenceGraph.cs index c7238310c..f37a76e13 100644 --- a/src/QuikGraph/Interfaces/Graphs/IMutableIncidenceGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IMutableIncidenceGraph.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph { @@ -18,12 +18,15 @@ public interface IMutableIncidenceGraph : IMutableGraphThe vertex. /// Predicate to remove edges. /// The number of removed edges. + /// is . + /// is . int RemoveOutEdgeIf([NotNull] TVertex vertex, [NotNull, InstantHandle] EdgePredicate predicate); /// /// Trims the out-edges of the given /// /// The vertex. + /// is . void ClearOutEdges([NotNull] TVertex vertex); /// diff --git a/src/QuikGraph/Interfaces/Graphs/IMutableUndirectedGraph.cs b/src/QuikGraph/Interfaces/Graphs/IMutableUndirectedGraph.cs index 6c9a46300..bf5847f58 100644 --- a/src/QuikGraph/Interfaces/Graphs/IMutableUndirectedGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IMutableUndirectedGraph.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph { @@ -19,12 +19,15 @@ public interface IMutableUndirectedGraph /// The vertex. /// Predicate to match edges. /// The number of removed edges. + /// is . + /// is . int RemoveAdjacentEdgeIf([NotNull] TVertex vertex, [NotNull, InstantHandle] EdgePredicate predicate); /// /// Clears adjacent edges of the given . /// /// The vertex. + /// is . void ClearAdjacentEdges([NotNull] TVertex vertex); } } \ No newline at end of file diff --git a/src/QuikGraph/Interfaces/Graphs/IMutableVertexAndEdgeSet.cs b/src/QuikGraph/Interfaces/Graphs/IMutableVertexAndEdgeSet.cs index a8753e513..441f8ba5f 100644 --- a/src/QuikGraph/Interfaces/Graphs/IMutableVertexAndEdgeSet.cs +++ b/src/QuikGraph/Interfaces/Graphs/IMutableVertexAndEdgeSet.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -18,6 +18,7 @@ public interface IMutableVertexAndEdgeSet /// /// The edge to add. /// True if the edge was added, false otherwise. + /// is . bool AddVerticesAndEdge([NotNull] TEdge edge); /// @@ -25,6 +26,9 @@ public interface IMutableVertexAndEdgeSet /// /// Edges to add. /// The number of edges added. + /// + /// is or at least one of them is . + /// int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edges); } } \ No newline at end of file diff --git a/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs b/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs index 1a42b6046..8ee723d88 100644 --- a/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -18,6 +18,8 @@ public interface ITermBidirectionalGraph : IBidirectionalGraph /// The vertex. /// Number of out terminals. + /// is . + /// is not part of the graph. [Pure] int OutTerminalCount([NotNull] TVertex vertex); @@ -27,15 +29,19 @@ public interface ITermBidirectionalGraph : IBidirectionalGraphThe vertex. /// Out terminal index. /// True if the out terminal is empty, false otherwise. + /// is . + /// is not part of the graph. [Pure] bool IsOutEdgesEmptyAt([NotNull] TVertex vertex, int terminal); /// - /// Gets the out degree for the requested terminal. + /// Gets the out-degree for the requested terminal. /// /// The vertex. /// Out terminal index. - /// The out degree on terminal . + /// The out-degree on terminal . + /// is . + /// is not part of the graph. [Pure] int OutDegreeAt([NotNull] TVertex vertex, int terminal); @@ -45,6 +51,8 @@ public interface ITermBidirectionalGraph : IBidirectionalGraphThe vertex. /// Out terminal index. /// The out-edges on terminal . + /// is . + /// is not part of the graph. [Pure] [NotNull, ItemNotNull] IEnumerable OutEdgesAt([NotNull] TVertex vertex, int terminal); @@ -56,6 +64,7 @@ public interface ITermBidirectionalGraph : IBidirectionalGraphOut terminal index. /// Out-edges found, otherwise null. /// True if was found or/and out-edges were found, false otherwise. + /// is . [Pure] [ContractAnnotation("=> true, edges:notnull;=> false, edges:null")] bool TryGetOutEdgesAt([NotNull] TVertex vertex, int terminal, [ItemNotNull] out IEnumerable edges); @@ -65,6 +74,8 @@ public interface ITermBidirectionalGraph : IBidirectionalGraph /// The vertex. /// Number of in terminals. + /// is . + /// is not part of the graph. [Pure] int InTerminalCount([NotNull] TVertex vertex); @@ -74,15 +85,19 @@ public interface ITermBidirectionalGraph : IBidirectionalGraphThe vertex. /// In terminal index. /// True if the in terminal is empty, false otherwise. + /// is . + /// is not part of the graph. [Pure] bool IsInEdgesEmptyAt([NotNull] TVertex vertex, int terminal); /// - /// Gets the in degree for the requested terminal. + /// Gets the in-degree for the requested terminal. /// /// The vertex. /// In terminal index. - /// The in degree on terminal . + /// The in-degree on terminal . + /// is . + /// is not part of the graph. [Pure] int InDegreeAt([NotNull] TVertex vertex, int terminal); @@ -92,6 +107,8 @@ public interface ITermBidirectionalGraph : IBidirectionalGraphThe vertex. /// In terminal index. /// The in-edges on terminal . + /// is . + /// is not part of the graph. [Pure] [NotNull, ItemNotNull] IEnumerable InEdgesAt([NotNull] TVertex vertex, int terminal); @@ -103,6 +120,7 @@ public interface ITermBidirectionalGraph : IBidirectionalGraphOut terminal index. /// In-edges found, otherwise null. /// True if was found or/and in-edges were found, false otherwise. + /// is . [Pure] [ContractAnnotation("=> true, edges:notnull;=> false, edges:null")] bool TryGetInEdgesAt([NotNull] TVertex vertex, int terminal, [ItemNotNull] out IEnumerable edges); diff --git a/src/QuikGraph/Interfaces/Vertices/IImplicitVertexSet.cs b/src/QuikGraph/Interfaces/Vertices/IImplicitVertexSet.cs index 193e62c48..57e3f007e 100644 --- a/src/QuikGraph/Interfaces/Vertices/IImplicitVertexSet.cs +++ b/src/QuikGraph/Interfaces/Vertices/IImplicitVertexSet.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph { @@ -13,6 +13,7 @@ public interface IImplicitVertexSet /// /// Vertex to check. /// True if the specified is contained in this set, false otherwise. + /// is . [Pure] bool ContainsVertex([NotNull] TVertex vertex); } diff --git a/src/QuikGraph/Interfaces/Vertices/IMutableVertexSet.cs b/src/QuikGraph/Interfaces/Vertices/IMutableVertexSet.cs index 37f46f8f9..b7bcb24c4 100644 --- a/src/QuikGraph/Interfaces/Vertices/IMutableVertexSet.cs +++ b/src/QuikGraph/Interfaces/Vertices/IMutableVertexSet.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using JetBrains.Annotations; namespace QuikGraph @@ -19,6 +19,7 @@ public interface IMutableVertexSet : IVertexSet /// /// Vertex to add. /// True if the vertex was added, false otherwise. + /// is . bool AddVertex([NotNull] TVertex vertex); /// @@ -26,6 +27,9 @@ public interface IMutableVertexSet : IVertexSet /// /// Vertices to add. /// The number of vertex added. + /// + /// is or at least one of them is . + /// int AddVertexRange([NotNull, ItemNotNull] IEnumerable vertices); /// @@ -38,6 +42,7 @@ public interface IMutableVertexSet : IVertexSet /// /// Vertex to remove. /// True if the vertex was removed, false otherwise. + /// is . bool RemoveVertex([NotNull] TVertex vertex); /// @@ -45,6 +50,7 @@ public interface IMutableVertexSet : IVertexSet /// /// Predicate to check on each vertex. /// The number of vertex removed. + /// is . int RemoveVertexIf([NotNull, InstantHandle] VertexPredicate predicate); } } \ No newline at end of file diff --git a/src/QuikGraph/Predicates/Graphs/FilteredBidirectionalGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredBidirectionalGraph.cs index c1e4509b6..5811e61a1 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredBidirectionalGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredBidirectionalGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -24,6 +24,9 @@ public class FilteredBidirectionalGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredBidirectionalGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/Graphs/FilteredEdgeListGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredEdgeListGraph.cs index 30ff67627..8913fd3fb 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredEdgeListGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredEdgeListGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -23,6 +23,9 @@ public sealed class FilteredEdgeListGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredEdgeListGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/Graphs/FilteredGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredGraph.cs index 6b1f2b2a3..a97e57b7b 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Predicates @@ -20,6 +20,9 @@ public class FilteredGraph : IGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, @@ -68,6 +71,7 @@ public FilteredGraph( /// /// Edge to check. /// True if the matches all predicates, false otherwise. + /// is . [Pure] protected bool FilterEdge([NotNull] TEdge edge) { diff --git a/src/QuikGraph/Predicates/Graphs/FilteredImplicitGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredImplicitGraph.cs index a1427499f..c7a96a57b 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredImplicitGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredImplicitGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -24,6 +24,9 @@ public class FilteredImplicitGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredImplicitGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/Graphs/FilteredImplicitVertexSetGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredImplicitVertexSetGraph.cs index 7448580cf..94900fd5f 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredImplicitVertexSetGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredImplicitVertexSetGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Predicates @@ -22,6 +22,9 @@ public class FilteredImplicitVertexSet /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredImplicitVertexSet( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs index e7f4c3225..fbf21d1a0 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredIncidenceGraph.cs @@ -24,6 +24,9 @@ public class FilteredIncidenceGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredIncidenceGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/Graphs/FilteredUndirectedGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredUndirectedGraph.cs index f7aa6cd77..27e74ae10 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredUndirectedGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredUndirectedGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -24,6 +24,9 @@ public sealed class FilteredUndirectedGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredUndirectedGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/Graphs/FilteredVertexAndEdgeListGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredVertexAndEdgeListGraph.cs index f9645e79c..7aee83cbe 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredVertexAndEdgeListGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredVertexAndEdgeListGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -24,6 +24,9 @@ public class FilteredVertexAndEdgeListGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredVertexAndEdgeListGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/Graphs/FilteredVertexListGraph.cs b/src/QuikGraph/Predicates/Graphs/FilteredVertexListGraph.cs index 779a6c041..30bb4823d 100644 --- a/src/QuikGraph/Predicates/Graphs/FilteredVertexListGraph.cs +++ b/src/QuikGraph/Predicates/Graphs/FilteredVertexListGraph.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -23,6 +23,9 @@ public class FilteredVertexListGraph /// Graph in which applying predicates. /// Predicate to match vertex that should be taken into account. /// Predicate to match edge that should be taken into account. + /// is . + /// is . + /// is . public FilteredVertexListGraph( [NotNull] TGraph baseGraph, [NotNull] VertexPredicate vertexPredicate, diff --git a/src/QuikGraph/Predicates/InDictionaryVertexPredicate.cs b/src/QuikGraph/Predicates/InDictionaryVertexPredicate.cs index 9a7c64899..81a283a3e 100644 --- a/src/QuikGraph/Predicates/InDictionaryVertexPredicate.cs +++ b/src/QuikGraph/Predicates/InDictionaryVertexPredicate.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -18,6 +18,7 @@ public sealed class InDictionaryVertexPredicate /// Initializes a new instance of the class. /// /// Vertex map. + /// is . public InDictionaryVertexPredicate([NotNull] IDictionary vertexMap) { _vertexMap = vertexMap ?? throw new ArgumentNullException(nameof(vertexMap)); @@ -29,6 +30,7 @@ public InDictionaryVertexPredicate([NotNull] IDictionary vertex /// Check if the implemented predicate is matched. /// Vertex to use in predicate. /// True if the vertex is in the vertex map, false otherwise. + /// is . [Pure] public bool Test([NotNull] TVertex vertex) { diff --git a/src/QuikGraph/Predicates/IsolatedVertexPredicate.cs b/src/QuikGraph/Predicates/IsolatedVertexPredicate.cs index d5f2af455..1220d2313 100644 --- a/src/QuikGraph/Predicates/IsolatedVertexPredicate.cs +++ b/src/QuikGraph/Predicates/IsolatedVertexPredicate.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Predicates @@ -18,6 +18,7 @@ public sealed class IsolatedVertexPredicate /// Initializes a new instance of the class. /// /// Graph to consider. + /// is . public IsolatedVertexPredicate([NotNull] IBidirectionalGraph visitedGraph) { _visitedGraph = visitedGraph ?? throw new ArgumentNullException(nameof(visitedGraph)); @@ -29,6 +30,7 @@ public IsolatedVertexPredicate([NotNull] IBidirectionalGraph vis /// Check if the implemented predicate is matched. /// Vertex to check. /// True if the vertex is isolated, false otherwise. + /// is . [Pure] public bool Test([NotNull] TVertex vertex) { diff --git a/src/QuikGraph/Predicates/ResidualEdgePrediate.cs b/src/QuikGraph/Predicates/ResidualEdgePrediate.cs index 879fb0fa7..5b7f7a220 100644 --- a/src/QuikGraph/Predicates/ResidualEdgePrediate.cs +++ b/src/QuikGraph/Predicates/ResidualEdgePrediate.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -16,6 +16,7 @@ public sealed class ResidualEdgePredicate /// Initializes a new instance of the class. /// /// Residual capacities per edge. + /// is . public ResidualEdgePredicate([NotNull] IDictionary residualCapacities) { ResidualCapacities = residualCapacities ?? throw new ArgumentNullException(nameof(residualCapacities)); @@ -33,12 +34,12 @@ public ResidualEdgePredicate([NotNull] IDictionary residualCapaci /// Check if the implemented predicate is matched. /// Edge to use in predicate. /// True if the edge is residual, false otherwise. + /// is . [Pure] public bool Test([NotNull] TEdge edge) { if (edge == null) throw new ArgumentNullException(nameof(edge)); - return 0 < ResidualCapacities[edge]; } } diff --git a/src/QuikGraph/Predicates/ReversedResidualEdgePredicate.cs b/src/QuikGraph/Predicates/ReversedResidualEdgePredicate.cs index b8b50051f..f5eef7cab 100644 --- a/src/QuikGraph/Predicates/ReversedResidualEdgePredicate.cs +++ b/src/QuikGraph/Predicates/ReversedResidualEdgePredicate.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using JetBrains.Annotations; @@ -17,6 +17,8 @@ public sealed class ReversedResidualEdgePredicate /// /// Residual capacities per edge. /// Map of edges and their reversed edges. + /// is . + /// is . public ReversedResidualEdgePredicate( [NotNull] IDictionary residualCapacities, [NotNull] IDictionary reversedEdges) @@ -43,6 +45,7 @@ public ReversedResidualEdgePredicate( /// Check if the implemented predicate is matched. /// Edge to use in predicate. /// True if the reversed edge is residual, false otherwise. + /// is . [Pure] public bool Test([NotNull] TEdge edge) { diff --git a/src/QuikGraph/Predicates/SinkVertexPredicate.cs b/src/QuikGraph/Predicates/SinkVertexPredicate.cs index fe418eba8..9d36a5edf 100644 --- a/src/QuikGraph/Predicates/SinkVertexPredicate.cs +++ b/src/QuikGraph/Predicates/SinkVertexPredicate.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; namespace QuikGraph.Predicates @@ -18,6 +18,7 @@ public sealed class SinkVertexPredicate /// Initializes a new instance of the class. /// /// Graph to consider. + /// is . public SinkVertexPredicate([NotNull] IIncidenceGraph visitedGraph) { _visitedGraph = visitedGraph ?? throw new ArgumentNullException(nameof(visitedGraph)); @@ -29,6 +30,7 @@ public SinkVertexPredicate([NotNull] IIncidenceGraph visitedGrap /// Check if the implemented predicate is matched. /// Vertex to use in predicate. /// True if the vertex is a sink, false otherwise. + /// is . [Pure] public bool Test([NotNull] TVertex vertex) { diff --git a/src/QuikGraph/Structures/Edges/Edge.cs b/src/QuikGraph/Structures/Edges/Edge.cs index 4d370ef67..c5cd56030 100644 --- a/src/QuikGraph/Structures/Edges/Edge.cs +++ b/src/QuikGraph/Structures/Edges/Edge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using JetBrains.Annotations; using QuikGraph.Constants; @@ -20,6 +20,8 @@ public class Edge : IEdge /// /// The source vertex. /// The target vertex. + /// is . + /// is . public Edge([NotNull] TVertex source, [NotNull] TVertex target) { if (source == null) diff --git a/src/QuikGraph/Structures/Edges/EquatableEdge.cs b/src/QuikGraph/Structures/Edges/EquatableEdge.cs index 522db0f3b..86246413f 100644 --- a/src/QuikGraph/Structures/Edges/EquatableEdge.cs +++ b/src/QuikGraph/Structures/Edges/EquatableEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -20,6 +20,8 @@ public class EquatableEdge : Edge, IEquatable /// The source vertex. /// The target vertex. + /// is . + /// is . public EquatableEdge([NotNull] TVertex source, [NotNull] TVertex target) : base(source, target) { diff --git a/src/QuikGraph/Structures/Edges/EquatableTaggedEdge.cs b/src/QuikGraph/Structures/Edges/EquatableTaggedEdge.cs index b80d9051c..57f59e4c9 100644 --- a/src/QuikGraph/Structures/Edges/EquatableTaggedEdge.cs +++ b/src/QuikGraph/Structures/Edges/EquatableTaggedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -23,6 +23,8 @@ public class EquatableTaggedEdge : EquatableEdge, ITagge /// The source vertex. /// The target vertex. /// Edge tag. + /// is . + /// is . public EquatableTaggedEdge([NotNull] TVertex source, [NotNull] TVertex target, [CanBeNull] TTag tag) : base(source, target) { diff --git a/src/QuikGraph/Structures/Edges/EquatableTermEdge.cs b/src/QuikGraph/Structures/Edges/EquatableTermEdge.cs index a89cc799f..951b4c163 100644 --- a/src/QuikGraph/Structures/Edges/EquatableTermEdge.cs +++ b/src/QuikGraph/Structures/Edges/EquatableTermEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -21,6 +21,8 @@ public class EquatableTermEdge : TermEdge, IEquatable /// The source vertex. /// The target vertex. + /// is . + /// is . public EquatableTermEdge([NotNull] TVertex source, [NotNull] TVertex target) : base(source, target) { @@ -34,6 +36,10 @@ public EquatableTermEdge([NotNull] TVertex source, [NotNull] TVertex target) /// The target vertex. /// The source terminal. /// The target terminal. + /// is . + /// is . + /// is negative. + /// is negative. public EquatableTermEdge([NotNull] TVertex source, [NotNull] TVertex target, int sourceTerminal, int targetTerminal) : base(source, target, sourceTerminal, targetTerminal) { diff --git a/src/QuikGraph/Structures/Edges/EquatableUndirectedEdge.cs b/src/QuikGraph/Structures/Edges/EquatableUndirectedEdge.cs index b269298bb..64d997896 100644 --- a/src/QuikGraph/Structures/Edges/EquatableUndirectedEdge.cs +++ b/src/QuikGraph/Structures/Edges/EquatableUndirectedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -20,6 +20,8 @@ public class EquatableUndirectedEdge : UndirectedEdge, IEquata /// /// The source vertex. /// The target vertex. + /// is . + /// is . public EquatableUndirectedEdge([NotNull] TVertex source, [NotNull] TVertex target) : base(source, target) { diff --git a/src/QuikGraph/Structures/Edges/SEdge.cs b/src/QuikGraph/Structures/Edges/SEdge.cs index 99c5cab95..caf31265a 100644 --- a/src/QuikGraph/Structures/Edges/SEdge.cs +++ b/src/QuikGraph/Structures/Edges/SEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Runtime.InteropServices; using JetBrains.Annotations; @@ -22,6 +22,8 @@ public struct SEdge : IEdge /// /// The source vertex. /// The target vertex. + /// is . + /// is . public SEdge([NotNull] TVertex source, [NotNull] TVertex target) { if (source == null) diff --git a/src/QuikGraph/Structures/Edges/SEquatableEdge.cs b/src/QuikGraph/Structures/Edges/SEquatableEdge.cs index 85d8c5173..ccbfd4811 100644 --- a/src/QuikGraph/Structures/Edges/SEquatableEdge.cs +++ b/src/QuikGraph/Structures/Edges/SEquatableEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; @@ -23,6 +23,8 @@ public struct SEquatableEdge : IEdge, IEquatable /// The source vertex. /// The target vertex. + /// is . + /// is . public SEquatableEdge([NotNull] TVertex source, [NotNull] TVertex target) { if (source == null) @@ -50,13 +52,8 @@ public override bool Equals(object obj) /// public bool Equals(SEquatableEdge other) { - // ReSharper disable ConstantConditionalAccessQualifier - // ReSharper disable ConstantNullCoalescingCondition - // Justification: Because of struct default constructor return EqualityComparer.Default.Equals(Source, other.Source) && EqualityComparer.Default.Equals(Target, other.Target); - // ReSharper restore ConstantNullCoalescingCondition - // ReSharper restore ConstantConditionalAccessQualifier } /// diff --git a/src/QuikGraph/Structures/Edges/SEquatableTaggedEdge.cs b/src/QuikGraph/Structures/Edges/SEquatableTaggedEdge.cs index 446f58a3a..01c293bda 100644 --- a/src/QuikGraph/Structures/Edges/SEquatableTaggedEdge.cs +++ b/src/QuikGraph/Structures/Edges/SEquatableTaggedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; using System.Diagnostics; using JetBrains.Annotations; @@ -25,6 +25,8 @@ public struct SEquatableTaggedEdge : IEdge, ITaggedThe source vertex. /// The target vertex. /// Edge tag. + /// is . + /// is . public SEquatableTaggedEdge([NotNull] TVertex source, [NotNull] TVertex target, [CanBeNull] TTag tag) { if (source == null) @@ -84,13 +86,8 @@ public override bool Equals(object obj) /// public bool Equals(SEquatableTaggedEdge other) { - // ReSharper disable ConstantConditionalAccessQualifier - // ReSharper disable ConstantNullCoalescingCondition - // Justification: Because of struct default constructor return EqualityComparer.Default.Equals(Source, other.Source) && EqualityComparer.Default.Equals(Target, other.Target); - // ReSharper restore ConstantNullCoalescingCondition - // ReSharper restore ConstantConditionalAccessQualifier } /// diff --git a/src/QuikGraph/Structures/Edges/SReversedEdge.cs b/src/QuikGraph/Structures/Edges/SReversedEdge.cs index 3de0c23f0..19ae02f49 100644 --- a/src/QuikGraph/Structures/Edges/SReversedEdge.cs +++ b/src/QuikGraph/Structures/Edges/SReversedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; @@ -23,6 +23,7 @@ public struct SReversedEdge : IEdge, IEquatable struct. /// /// Original edge. + /// is . public SReversedEdge([NotNull] TEdge originalEdge) { if (originalEdge == null) diff --git a/src/QuikGraph/Structures/Edges/STaggedEdge.cs b/src/QuikGraph/Structures/Edges/STaggedEdge.cs index 3d2c267ab..b1eb9c009 100644 --- a/src/QuikGraph/Structures/Edges/STaggedEdge.cs +++ b/src/QuikGraph/Structures/Edges/STaggedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; using System.Diagnostics; using JetBrains.Annotations; @@ -25,6 +25,8 @@ public struct STaggedEdge : IEdge, ITagged /// The source vertex. /// The target vertex. /// Edge tag. + /// is . + /// is . public STaggedEdge([NotNull] TVertex source, [NotNull] TVertex target, [CanBeNull] TTag tag) { if (source == null) diff --git a/src/QuikGraph/Structures/Edges/STaggedUndirectedEdge.cs b/src/QuikGraph/Structures/Edges/STaggedUndirectedEdge.cs index 18aa97229..25c146bab 100644 --- a/src/QuikGraph/Structures/Edges/STaggedUndirectedEdge.cs +++ b/src/QuikGraph/Structures/Edges/STaggedUndirectedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Diagnostics; @@ -25,6 +25,11 @@ public struct STaggedUndirectedEdge : IUndirectedEdge, I /// The source vertex. /// The target vertex. /// Edge tag. + /// is . + /// is . + /// + /// is not lower than when using . + /// public STaggedUndirectedEdge([NotNull] TVertex source, [NotNull] TVertex target, [CanBeNull] TTag tag) { if (source == null) diff --git a/src/QuikGraph/Structures/Edges/SUndirectedEdge.cs b/src/QuikGraph/Structures/Edges/SUndirectedEdge.cs index d3140a8a7..a36e396bc 100644 --- a/src/QuikGraph/Structures/Edges/SUndirectedEdge.cs +++ b/src/QuikGraph/Structures/Edges/SUndirectedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Runtime.InteropServices; using JetBrains.Annotations; @@ -22,6 +22,8 @@ public struct SUndirectedEdge : IUndirectedEdge /// /// The source vertex. /// The target vertex. + /// is . + /// is . public SUndirectedEdge([NotNull] TVertex source, [NotNull] TVertex target) { if (source == null) diff --git a/src/QuikGraph/Structures/Edges/TaggedEdge.cs b/src/QuikGraph/Structures/Edges/TaggedEdge.cs index 4a849036f..ac9c0a4f9 100644 --- a/src/QuikGraph/Structures/Edges/TaggedEdge.cs +++ b/src/QuikGraph/Structures/Edges/TaggedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -22,6 +22,8 @@ public class TaggedEdge : Edge, ITagged /// The source vertex. /// The target vertex. /// Edge tag. + /// is . + /// is . public TaggedEdge([NotNull] TVertex source, [NotNull] TVertex target, [CanBeNull] TTag tag) : base(source, target) { diff --git a/src/QuikGraph/Structures/Edges/TaggedUndirectedEdge.cs b/src/QuikGraph/Structures/Edges/TaggedUndirectedEdge.cs index 99c735feb..1b6dea842 100644 --- a/src/QuikGraph/Structures/Edges/TaggedUndirectedEdge.cs +++ b/src/QuikGraph/Structures/Edges/TaggedUndirectedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -23,6 +23,8 @@ public class TaggedUndirectedEdge : UndirectedEdge, ITag /// The source vertex. /// The target vertex. /// Edge tag. + /// is . + /// is . public TaggedUndirectedEdge([NotNull] TVertex source, [NotNull] TVertex target, [CanBeNull] TTag tag) : base(source, target) { diff --git a/src/QuikGraph/Structures/Edges/TermEdge.cs b/src/QuikGraph/Structures/Edges/TermEdge.cs index 1d3369228..9b590b124 100644 --- a/src/QuikGraph/Structures/Edges/TermEdge.cs +++ b/src/QuikGraph/Structures/Edges/TermEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using JetBrains.Annotations; using QuikGraph.Constants; @@ -21,6 +21,8 @@ public class TermEdge : ITermEdge /// /// The source vertex. /// The target vertex. + /// is . + /// is . public TermEdge([NotNull] TVertex source, [NotNull] TVertex target) : this(source, target, 0, 0) { @@ -34,6 +36,10 @@ public TermEdge([NotNull] TVertex source, [NotNull] TVertex target) /// The target vertex. /// The source terminal. /// The target terminal. + /// is . + /// is . + /// is negative. + /// is negative. public TermEdge([NotNull] TVertex source, [NotNull] TVertex target, int sourceTerminal, int targetTerminal) { if (source == null) diff --git a/src/QuikGraph/Structures/Edges/UndirectedEdge.cs b/src/QuikGraph/Structures/Edges/UndirectedEdge.cs index 25989fb4d..bfced45ea 100644 --- a/src/QuikGraph/Structures/Edges/UndirectedEdge.cs +++ b/src/QuikGraph/Structures/Edges/UndirectedEdge.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using JetBrains.Annotations; @@ -21,6 +21,11 @@ public class UndirectedEdge : IUndirectedEdge /// /// The source vertex. /// The target vertex. + /// is . + /// is . + /// + /// is not lower than when using . + /// public UndirectedEdge([NotNull] TVertex source, [NotNull] TVertex target) { if (source == null) diff --git a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs index 704ea7031..138738166 100644 --- a/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/AdjacencyGraph.cs @@ -393,11 +393,7 @@ public virtual bool AddVerticesAndEdge(TEdge edge) return AddEdgeInternal(edge); } - /// - /// Adds a range of edges to the graph. - /// - /// Edges to add. - /// The number of edges that were added. + /// public int AddVerticesAndEdgeRange(IEnumerable edges) { if (edges is null) @@ -627,6 +623,7 @@ public void ClearOutEdges(TVertex vertex) /// Clears edges of the given . /// /// The vertex. + /// is . public void ClearEdges([NotNull] TVertex vertex) { ClearOutEdges(vertex); diff --git a/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs index 2ddbc35fd..8010ebe28 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayAdjacencyGraph.cs @@ -28,20 +28,21 @@ public sealed class ArrayAdjacencyGraph : IVertexAndEdgeListGrap /// /// Initializes a new instance of the class. /// - /// Graph to visit. - public ArrayAdjacencyGraph([NotNull] IVertexAndEdgeListGraph visitedGraph) + /// Wrapped graph. + /// is . + public ArrayAdjacencyGraph([NotNull] IVertexAndEdgeListGraph baseGraph) { - if (visitedGraph is null) - throw new ArgumentNullException(nameof(visitedGraph)); + if (baseGraph is null) + throw new ArgumentNullException(nameof(baseGraph)); - AllowParallelEdges = visitedGraph.AllowParallelEdges; - _vertexOutEdges = new Dictionary(visitedGraph.VertexCount); - EdgeCount = visitedGraph.EdgeCount; - foreach (TVertex vertex in visitedGraph.Vertices) + AllowParallelEdges = baseGraph.AllowParallelEdges; + _vertexOutEdges = new Dictionary(baseGraph.VertexCount); + EdgeCount = baseGraph.EdgeCount; + foreach (TVertex vertex in baseGraph.Vertices) { _vertexOutEdges.Add( vertex, - visitedGraph.OutEdges(vertex).ToArray()); + baseGraph.OutEdges(vertex).ToArray()); } } diff --git a/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs index f1bba93c4..d03f842ff 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayBidirectionalGraph.cs @@ -48,19 +48,20 @@ public InOutEdges( /// /// Initializes a new instance of the class. /// - /// Graph to visit. - public ArrayBidirectionalGraph([NotNull] IBidirectionalGraph visitedGraph) + /// Wrapped graph. + /// is . + public ArrayBidirectionalGraph([NotNull] IBidirectionalGraph baseGraph) { - if (visitedGraph is null) - throw new ArgumentNullException(nameof(visitedGraph)); + if (baseGraph is null) + throw new ArgumentNullException(nameof(baseGraph)); - AllowParallelEdges = visitedGraph.AllowParallelEdges; - _vertexEdges = new Dictionary(visitedGraph.VertexCount); - EdgeCount = visitedGraph.EdgeCount; - foreach (TVertex vertex in visitedGraph.Vertices) + AllowParallelEdges = baseGraph.AllowParallelEdges; + _vertexEdges = new Dictionary(baseGraph.VertexCount); + EdgeCount = baseGraph.EdgeCount; + foreach (TVertex vertex in baseGraph.Vertices) { - TEdge[] outEdges = visitedGraph.OutEdges(vertex).ToArray(); - TEdge[] inEdges = visitedGraph.InEdges(vertex).ToArray(); + TEdge[] outEdges = baseGraph.OutEdges(vertex).ToArray(); + TEdge[] inEdges = baseGraph.InEdges(vertex).ToArray(); _vertexEdges.Add(vertex, new InOutEdges(outEdges, inEdges)); } } diff --git a/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs index 560c04298..f0d1d8fb8 100644 --- a/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ArrayUndirectedGraph.cs @@ -31,24 +31,25 @@ public sealed class ArrayUndirectedGraph : IUndirectedGraph /// Initializes a new instance of the class. /// - /// Graph to visit. - public ArrayUndirectedGraph([NotNull] IUndirectedGraph visitedGraph) + /// Wrapped graph. + /// is . + public ArrayUndirectedGraph([NotNull] IUndirectedGraph baseGraph) { - if (visitedGraph is null) - throw new ArgumentNullException(nameof(visitedGraph)); - - AllowParallelEdges = visitedGraph.AllowParallelEdges; - EdgeEqualityComparer = visitedGraph.EdgeEqualityComparer; - EdgeCount = visitedGraph.EdgeCount; - _vertexEdges = new Dictionary(visitedGraph.VertexCount); - foreach (TVertex vertex in visitedGraph.Vertices) + if (baseGraph is null) + throw new ArgumentNullException(nameof(baseGraph)); + + AllowParallelEdges = baseGraph.AllowParallelEdges; + EdgeEqualityComparer = baseGraph.EdgeEqualityComparer; + EdgeCount = baseGraph.EdgeCount; + _vertexEdges = new Dictionary(baseGraph.VertexCount); + foreach (TVertex vertex in baseGraph.Vertices) { _vertexEdges.Add( vertex, - visitedGraph.AdjacentEdges(vertex).ToArray()); + baseGraph.AdjacentEdges(vertex).ToArray()); } - _edges = new List(visitedGraph.Edges); + _edges = new List(baseGraph.Edges); } /// @@ -199,10 +200,7 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) #if SUPPORTS_SERIALIZATION && NETSTANDARD2_0 #region ISerializable - - /// - /// Constructor used during runtime serialization. - /// + private ArrayUndirectedGraph(SerializationInfo info, StreamingContext context) { AllowParallelEdges = (bool)info.GetValue("AllowParallelEdges", typeof(bool)); diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs index e1438efe2..b59dc5bcb 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalAdapterGraph.cs @@ -27,6 +27,7 @@ public class BidirectionalAdapterGraph : IBidirectionalGraph class. /// /// Wrapped graph. + /// is . public BidirectionalAdapterGraph([NotNull] IVertexAndEdgeListGraph baseGraph) { _baseGraph = baseGraph ?? throw new ArgumentNullException(nameof(baseGraph)); diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs index 026ff80ae..8cb978449 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalGraph.cs @@ -765,6 +765,9 @@ public void ClearEdges(TVertex vertex) /// /// The vertex. /// Factory method to create an edge. + /// is . + /// is . + /// is not part of the graph. public void MergeVertex( [NotNull] TVertex vertex, [NotNull, InstantHandle] EdgeFactory edgeFactory) @@ -804,6 +807,8 @@ public void MergeVertex( /// /// Predicate to match vertices. /// Factory method to create an edge. + /// is . + /// is . public void MergeVerticesIf( [NotNull, InstantHandle] VertexPredicate vertexPredicate, [NotNull, InstantHandle] EdgeFactory edgeFactory) diff --git a/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs b/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs index 073c5704b..fdeeb4de0 100644 --- a/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs +++ b/src/QuikGraph/Structures/Graphs/BidirectionalMatrixGraph.cs @@ -27,6 +27,7 @@ public class BidirectionalMatrixGraph : IBidirectionalGraph, /// Initializes a new instance of the class. /// /// Number of vertices. + /// is is negative or equal to 0. public BidirectionalMatrixGraph(int vertexCount) { if (vertexCount <= 0) @@ -378,6 +379,7 @@ public void Clear() /// The vertex. /// Edge predicate. /// Number of edges removed. + /// is . public int RemoveInEdgeIf(int vertex, [NotNull, InstantHandle] EdgePredicate predicate) { if (predicate is null) @@ -450,6 +452,7 @@ public void ClearEdges(int vertex) /// The vertex. /// Predicate to remove edges. /// The number of removed edges. + /// is . public int RemoveOutEdgeIf(int vertex, [NotNull, InstantHandle] EdgePredicate predicate) { if (predicate is null) @@ -503,6 +506,7 @@ public void ClearOutEdges(int vertex) #region IMutableEdgeListGraph /// + /// is already present in graph. public bool AddEdge(TEdge edge) { if (edge == null) @@ -593,7 +597,7 @@ protected virtual void OnEdgeRemoved([NotNull] TEdge edge) /// /// is not implemented for this kind of graph. /// - /// This method is not supported. + /// This method is not supported. public int RemoveEdgeIf(EdgePredicate predicate) { throw new NotSupportedException(); diff --git a/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs b/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs index 8ec3ae9db..5b59e6bac 100644 --- a/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ClusteredAdjacencyGraph.cs @@ -30,6 +30,7 @@ public class ClusteredAdjacencyGraph /// Initializes a new instance of the class. /// /// Graph to wrap. + /// is . public ClusteredAdjacencyGraph([NotNull] AdjacencyGraph wrappedGraph) { Parent = null; @@ -41,6 +42,7 @@ public ClusteredAdjacencyGraph([NotNull] AdjacencyGraph wrappedG /// Initializes a new instance of the class. /// /// Parent graph. + /// is . public ClusteredAdjacencyGraph([NotNull] ClusteredAdjacencyGraph parentGraph) { Parent = parentGraph ?? throw new ArgumentNullException(nameof(parentGraph)); @@ -231,6 +233,7 @@ public TEdge OutEdge(TVertex vertex, int index) /// /// Vertex to add. /// True if the vertex was added, false otherwise. + /// is . public virtual bool AddVertex([NotNull] TVertex vertex) { if (vertex == null) @@ -250,6 +253,9 @@ public virtual bool AddVertex([NotNull] TVertex vertex) /// /// Vertices to add. /// The number of vertex added. + /// + /// is or at least one of them is . + /// public virtual int AddVertexRange([NotNull, ItemNotNull] IEnumerable vertices) { if (vertices is null) @@ -296,6 +302,7 @@ private void RemoveVertexInternal([NotNull] TVertex vertex) /// /// Vertex to remove. /// True if the vertex was removed, false otherwise. + /// is . public virtual bool RemoveVertex([NotNull] TVertex vertex) { if (vertex == null) @@ -314,6 +321,7 @@ public virtual bool RemoveVertex([NotNull] TVertex vertex) /// /// Predicate to check on each vertex. /// The number of vertex removed. + /// is . public int RemoveVertexIf([NotNull, InstantHandle] VertexPredicate predicate) { if (predicate is null) @@ -335,6 +343,7 @@ public int RemoveVertexIf([NotNull, InstantHandle] VertexPredicate pred /// /// The edge to add. /// True if the edge was added, false otherwise. + /// is . public virtual bool AddVerticesAndEdge([NotNull] TEdge edge) { if (edge == null) @@ -350,6 +359,9 @@ public virtual bool AddVerticesAndEdge([NotNull] TEdge edge) /// /// Edges to add. /// The number of edges added. + /// + /// is or at least one of them is . + /// public int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edges) { if (edges is null) @@ -366,6 +378,7 @@ public int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edg /// /// An edge. /// True if the edge was added, false otherwise. + /// is . public virtual bool AddEdge([NotNull] TEdge edge) { if (edge == null) @@ -383,6 +396,9 @@ public virtual bool AddEdge([NotNull] TEdge edge) /// /// Edges to add. /// The number of edges successfully added to this graph. + /// + /// is or at least one of them is . + /// public int AddEdgeRange([NotNull, ItemNotNull] IEnumerable edges) { if (edges is null) @@ -425,6 +441,7 @@ private void RemoveEdgeInternal([NotNull] TEdge edge) /// /// Edge to remove. /// True if the was successfully removed, false otherwise. + /// is . public virtual bool RemoveEdge([NotNull] TEdge edge) { if (edge == null) @@ -443,6 +460,7 @@ public virtual bool RemoveEdge([NotNull] TEdge edge) /// /// Predicate to check if an edge should be removed. /// The number of edges removed. + /// is . public int RemoveEdgeIf([NotNull, InstantHandle] EdgePredicate predicate) { if (predicate is null) @@ -466,6 +484,8 @@ public int RemoveEdgeIf([NotNull, InstantHandle] EdgePredicate p /// The vertex. /// Predicate to remove edges. /// The number of removed edges. + /// is . + /// is . public int RemoveOutEdgeIf([NotNull] TVertex vertex, [NotNull, InstantHandle] EdgePredicate predicate) { if (vertex == null) @@ -483,6 +503,7 @@ public int RemoveOutEdgeIf([NotNull] TVertex vertex, [NotNull, InstantHandle] Ed /// Clears the out-edges of the given /// /// The vertex. + /// is . public void ClearOutEdges([NotNull] TVertex vertex) { if (vertex == null) diff --git a/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs b/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs index 2a8ed4203..9bc6a6738 100644 --- a/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs +++ b/src/QuikGraph/Structures/Graphs/CompressedSparseRowGraph.cs @@ -55,31 +55,32 @@ private CompressedSparseRowGraph( } /// - /// Converts the given to a . + /// Converts the given to a . /// - /// Graph to convert. + /// Graph to convert. /// Edge type. /// A corresponding . + /// is . [NotNull] public static CompressedSparseRowGraph FromGraph( - [NotNull] IVertexAndEdgeListGraph visitedGraph) + [NotNull] IVertexAndEdgeListGraph graph) where TEdge : IEdge { - if (visitedGraph is null) - throw new ArgumentNullException(nameof(visitedGraph)); + if (graph is null) + throw new ArgumentNullException(nameof(graph)); - var outEdgeStartRanges = new Dictionary(visitedGraph.VertexCount); - var outEdges = new TVertex[visitedGraph.EdgeCount]; + var outEdgeStartRanges = new Dictionary(graph.VertexCount); + var outEdges = new TVertex[graph.EdgeCount]; int start = 0; int index = 0; - foreach (TVertex vertex in visitedGraph.Vertices) + foreach (TVertex vertex in graph.Vertices) { - int end = start + visitedGraph.OutDegree(vertex); + int end = start + graph.OutDegree(vertex); var range = new Range(start, end); outEdgeStartRanges.Add(vertex, range); - foreach (TEdge edge in visitedGraph.OutEdges(vertex)) + foreach (TEdge edge in graph.OutEdges(vertex)) { outEdges[index++] = edge.Target; } diff --git a/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs index 93458cbff..1b1eefb85 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateBidirectionalIncidenceGraph.cs @@ -23,6 +23,8 @@ public class DelegateBidirectionalIncidenceGraph : DelegateIncid /// Note that get of edges is delegated so you may have bugs related /// to parallel edges due to the delegated implementation. /// + /// is . + /// is . public DelegateBidirectionalIncidenceGraph( [NotNull] TryFunc> tryGetOutEdges, [NotNull] TryFunc> tryGetInEdges, diff --git a/src/QuikGraph/Structures/Graphs/DelegateImplicitGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateImplicitGraph.cs index f1b5d437a..5be8af051 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateImplicitGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateImplicitGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -22,6 +22,7 @@ public class DelegateImplicitGraph : IImplicitGraph + /// is . public DelegateImplicitGraph( [NotNull] TryFunc> tryGetOutEdges, bool allowParallelEdges = true) diff --git a/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs index d3a5a021a..c02c2a055 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs @@ -22,6 +22,7 @@ public class DelegateImplicitUndirectedGraph : IImplicitUndirect /// Note that get of edges is delegated so you may have bugs related /// to parallel edges due to the delegated implementation. /// + /// is . public DelegateImplicitUndirectedGraph( [NotNull] TryFunc> tryGetAdjacentEdges, bool allowParallelEdges = true) @@ -141,7 +142,9 @@ internal virtual bool TryGetAdjacentEdgesInternal([NotNull] TVertex vertex, out /// The vertex. /// Edges found, otherwise null. /// True if was found or/and edges were found, false otherwise. + /// is . [Pure] + [ContractAnnotation("=> true, edges:notnull;=> false, edges:null")] public bool TryGetAdjacentEdges([NotNull] TVertex vertex, out IEnumerable edges) { return TryGetAdjacentEdgesInternal(vertex, out edges); diff --git a/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs index ff9ef1c98..bc24007cd 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateIncidenceGraph.cs @@ -22,6 +22,7 @@ public class DelegateIncidenceGraph : DelegateImplicitGraph + /// is . public DelegateIncidenceGraph( [NotNull] TryFunc> tryGetOutEdges, bool allowParallelEdges = true) diff --git a/src/QuikGraph/Structures/Graphs/DelegateUndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateUndirectedGraph.cs index f65883638..fcd27be8b 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateUndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateUndirectedGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -25,6 +25,8 @@ public class DelegateUndirectedGraph : DelegateImplicitUndirecte /// Note that get of edges is delegated so you may have bugs related /// to parallel edges due to the delegated implementation. /// + /// is . + /// is . public DelegateUndirectedGraph( [NotNull, ItemNotNull] IEnumerable vertices, [NotNull] TryFunc> tryGetAdjacentEdges, diff --git a/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs index 0bcbdcb45..e36f6f62d 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateVertexAndEdgeListGraph.cs @@ -25,6 +25,8 @@ public class DelegateVertexAndEdgeListGraph : DelegateIncidenceG /// Note that get of edges is delegated so you may have bugs related /// to parallel edges due to the delegated implementation. /// + /// is . + /// is . public DelegateVertexAndEdgeListGraph( [NotNull, ItemNotNull] IEnumerable vertices, [NotNull] TryFunc> tryGetOutEdges, diff --git a/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs b/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs index 0ff275fbd..5640164b7 100644 --- a/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs +++ b/src/QuikGraph/Structures/Graphs/EdgeListGraph.cs @@ -135,6 +135,7 @@ private bool ContainsEdge(TVertex source, TVertex target) /// /// The edge to add. /// True if the edge was added, false otherwise. + /// is . public bool AddVerticesAndEdge([NotNull] TEdge edge) { return AddEdge(edge); @@ -145,6 +146,9 @@ public bool AddVerticesAndEdge([NotNull] TEdge edge) /// /// Edges to add. /// The number of edges added. + /// + /// is or at least one of them is . + /// public int AddVerticesAndEdgeRange([NotNull, ItemNotNull] IEnumerable edges) { if (edges is null) diff --git a/src/QuikGraph/Structures/Graphs/ReversedBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/ReversedBidirectionalGraph.cs index ed98960c3..df0cbfc55 100644 --- a/src/QuikGraph/Structures/Graphs/ReversedBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/ReversedBidirectionalGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -23,6 +23,7 @@ public sealed class ReversedBidirectionalGraph : IBidirectionalG /// Initializes a new instance of the class. /// /// Original graph to reverse. + /// is . public ReversedBidirectionalGraph([NotNull] IBidirectionalGraph originalGraph) { OriginalGraph = originalGraph ?? throw new ArgumentNullException(nameof(originalGraph)); diff --git a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs index b6f02e74d..b84fc621a 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedBidirectionalGraph.cs @@ -33,6 +33,7 @@ public sealed class UndirectedBidirectionalGraph : IUndirectedGr /// Initializes a new instance of the class. /// /// Bidirectional graph. + /// is . public UndirectedBidirectionalGraph([NotNull] IBidirectionalGraph originalGraph) { OriginalGraph = originalGraph ?? throw new ArgumentNullException(nameof(originalGraph)); @@ -163,7 +164,7 @@ public bool IsAdjacentEdgesEmpty(TVertex vertex) /// /// is not supported for this kind of graph. /// - /// This operation is not supported. + /// This operation is not supported. public TEdge AdjacentEdge(TVertex vertex, int index) { throw new NotSupportedException(); @@ -194,10 +195,7 @@ public bool TryGetEdge(TVertex source, TVertex target, out TEdge edge) #if SUPPORTS_SERIALIZATION && NETSTANDARD2_0 #region ISerializable - - /// - /// Constructor used during runtime serialization. - /// + private UndirectedBidirectionalGraph(SerializationInfo info, StreamingContext context) : this((IBidirectionalGraph)info.GetValue("OriginalGraph", typeof(IBidirectionalGraph))) { diff --git a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs index 8e54fcb50..72b8b0f35 100644 --- a/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/UndirectedGraph.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -64,6 +64,7 @@ public UndirectedGraph(bool allowParallelEdges) /// /// Indicates if parallel edges are allowed. /// Equality comparer to use to compare edges. + /// is . public UndirectedGraph(bool allowParallelEdges, [NotNull] EdgeEqualityComparer edgeEqualityComparer) { AllowParallelEdges = allowParallelEdges; @@ -116,6 +117,7 @@ private delegate void ReorderVertices( /// /// Vertex to get adjacent ones. /// Set of adjacent vertices. + /// is . [Pure] [NotNull, ItemNotNull] public IEnumerable AdjacentVertices([NotNull] TVertex vertex) @@ -485,6 +487,7 @@ public void ClearAdjacentEdges(TVertex vertex) /// Clears edges of the given . /// /// The vertex. + /// is . public void ClearEdges([NotNull] TVertex vertex) { ClearAdjacentEdges(vertex); @@ -680,6 +683,9 @@ private int RemoveEdgesInternal([NotNull, ItemNotNull] ICollection edgesT /// /// Edges to remove. /// The number of removed edges. + /// + /// is or at least one of them is . + /// public int RemoveEdges([NotNull, ItemNotNull] IEnumerable edges) { if (edges is null) diff --git a/tests/QuikGraph.Serialization.Tests/DirectedGraphMLExtensionsTests.cs b/tests/QuikGraph.Serialization.Tests/DirectedGraphMLExtensionsTests.cs index 31fdf3bc3..65bde47cc 100644 --- a/tests/QuikGraph.Serialization.Tests/DirectedGraphMLExtensionsTests.cs +++ b/tests/QuikGraph.Serialization.Tests/DirectedGraphMLExtensionsTests.cs @@ -299,7 +299,7 @@ public void ToDirectedGraphML_WithColors() var random = new Random(123456); foreach (AdjacencyGraph> graph in TestGraphFactory.GetAdjacencyGraphs_All()) { - Dictionary vertexColors = graph.Vertices.ToDictionary( + Dictionary verticesColors = graph.Vertices.ToDictionary( vertex => vertex, _ => (GraphColor)random.Next(0, 3)); @@ -307,7 +307,7 @@ public void ToDirectedGraphML_WithColors() vertex => { Assert.IsNotNull(vertex); - return vertexColors[vertex]; + return verticesColors[vertex]; }); Assert.IsNotNull(graph); @@ -316,7 +316,7 @@ public void ToDirectedGraphML_WithColors() foreach (DirectedGraphNode node in directedGraph.Nodes) { Assert.AreEqual( - ColorToStringColor(vertexColors[node.Id]), + ColorToStringColor(verticesColors[node.Id]), node.Background); } } diff --git a/tests/QuikGraph.Serialization.Tests/GraphMLSerializerTests.cs b/tests/QuikGraph.Serialization.Tests/GraphMLSerializerTests.cs index 1244dbff3..0d2fa0c7c 100644 --- a/tests/QuikGraph.Serialization.Tests/GraphMLSerializerTests.cs +++ b/tests/QuikGraph.Serialization.Tests/GraphMLSerializerTests.cs @@ -251,7 +251,7 @@ public void SerializeToGraphML_Throws() [Test] public void SerializeToGraphML_Throws_InvalidData() { - AssertSerializationFail(new TestGraphArrayDefaultValue()); + AssertSerializationFail(new TestGraphArrayDefaultValue()); AssertSerializationFail(new TestGraphNoGetter()); AssertSerializationFail(new TestGraphNullDefaultValue()); AssertSerializationFail(new TestGraphWrongDefaultValue()); diff --git a/tests/QuikGraph.Tests/Algorithms/RandomGraphFactoryTests.cs b/tests/QuikGraph.Tests/Algorithms/RandomGraphFactoryTests.cs index 6d36632b2..c5bb8f54c 100644 --- a/tests/QuikGraph.Tests/Algorithms/RandomGraphFactoryTests.cs +++ b/tests/QuikGraph.Tests/Algorithms/RandomGraphFactoryTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using NUnit.Framework; using QuikGraph.Algorithms; @@ -126,8 +126,21 @@ public void Create() { var graph = new AdjacencyGraph>(); - // With self edge + // With isolated vertices only int v = 0; + RandomGraphFactory.Create( + graph, + () => ++v, + (source, target) => new EquatableEdge(source, target), + new Random(123456), + 2, + 0, + true); + AssertHasVertices(graph, new[] { 1, 2 }); + AssertNoEdge(graph); + + // With self edge + v = 0; RandomGraphFactory.Create( graph, () => ++v, @@ -374,13 +387,6 @@ public void Create_Throws() (source, target) => new Edge(source, target), random, 1, -1, false)); - Assert.Throws( - () => RandomGraphFactory.Create( - graph, - () => 1, - (source, target) => new Edge(source, target), - random, - 1, 0, false)); Assert.Throws( () => RandomGraphFactory.Create( graph, @@ -402,8 +408,21 @@ public void Create_Undirected() { var graph = new UndirectedGraph>(); - // With self edge + // With isolated vertices only int v = 0; + RandomGraphFactory.Create( + graph, + () => ++v, + (source, target) => new EquatableEdge(source, target), + new Random(123456), + 2, + 0, + true); + AssertHasVertices(graph, new[] { 1, 2 }); + AssertNoEdge(graph); + + // With self edge + v = 0; RandomGraphFactory.Create( graph, () => ++v, @@ -650,13 +669,6 @@ public void Create_Undirected_Throws() (source, target) => new Edge(source, target), random, 1, -1, false)); - Assert.Throws( - () => RandomGraphFactory.Create( - graph, - () => 1, - (source, target) => new Edge(source, target), - random, - 1, 0, false)); Assert.Throws( () => RandomGraphFactory.Create( graph, diff --git a/tests/QuikGraph.Tests/Algorithms/ShortestPath/YenShortestPathsAlgorithmTests.cs b/tests/QuikGraph.Tests/Algorithms/ShortestPath/YenShortestPathsAlgorithmTests.cs index 54a2fc3c9..895df5296 100644 --- a/tests/QuikGraph.Tests/Algorithms/ShortestPath/YenShortestPathsAlgorithmTests.cs +++ b/tests/QuikGraph.Tests/Algorithms/ShortestPath/YenShortestPathsAlgorithmTests.cs @@ -17,6 +17,7 @@ public void Constructor() Func, double> Weights = _ => 1.0; var graph = new AdjacencyGraph>(); + graph.AddVertexRange(new[] { 1, 2 }); // ReSharper disable ObjectCreationAsStatement Assert.DoesNotThrow(() => new YenShortestPathsAlgorithm(graph, 1, 2, int.MaxValue)); Assert.DoesNotThrow(() => new YenShortestPathsAlgorithm(graph, 1, 2, 10)); @@ -30,10 +31,26 @@ public void Constructor_Throws() { // ReSharper disable ObjectCreationAsStatement // ReSharper disable AssignNullToNotNullAttribute - var graph = new AdjacencyGraph>(); var vertex1 = new TestVertex("1"); var vertex2 = new TestVertex("2"); + var graph = new AdjacencyGraph>(); + Assert.Throws( + () => new YenShortestPathsAlgorithm(graph, vertex1, vertex2, int.MaxValue)); + + graph = new AdjacencyGraph>(); + graph.AddVertex(vertex1); + Assert.Throws( + () => new YenShortestPathsAlgorithm(graph, vertex1, vertex2, int.MaxValue)); + + graph = new AdjacencyGraph>(); + graph.AddVertex(vertex2); + Assert.Throws( + () => new YenShortestPathsAlgorithm(graph, vertex1, vertex2, int.MaxValue)); + + graph = new AdjacencyGraph>(); + graph.AddVertexRange(new[] { vertex1, vertex2 }); + Assert.Throws( () => new YenShortestPathsAlgorithm(null, vertex1, vertex2, int.MaxValue)); Assert.Throws( @@ -58,32 +75,20 @@ public void Constructor_Throws() } /// - /// Attempt to use non existing vertices. - /// - [Test] - public void EmptyGraph() - { - var graph = new AdjacencyGraph>(true); - - var algorithm = new YenShortestPathsAlgorithm(graph, '1', '5', 10); - // ReSharper disable once ReturnValueOfPureMethodIsNotUsed - Assert.Throws(() => algorithm.Execute()); - } - - /// - /// Attempt to use for graph that only have one vertex. + /// Attempt to use for simple graph. /// Expecting that Dijkstra’s algorithm couldn't find any ways. /// [Test] - public void OneVertexGraph() + public void SimpleNoPathGraph() { var graph = new AdjacencyGraph>(true); - graph.AddVertexRange("1"); + graph.AddVertex('1'); // ReSharper disable ReturnValueOfPureMethodIsNotUsed var algorithm = new YenShortestPathsAlgorithm(graph, '1', '1', 10); Assert.Throws(() => algorithm.Execute()); + graph.AddVertex('2'); algorithm = new YenShortestPathsAlgorithm(graph, '1', '2', 10); Assert.Throws(() => algorithm.Execute()); // ReSharper restore ReturnValueOfPureMethodIsNotUsed From 0763f12260fddffb696d7b1a7bb7b48c73a603b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 18 Oct 2021 00:43:22 +0200 Subject: [PATCH 07/39] Remove misleading duplicated code. --- .../CyclePoppingRandomTreeAlgorithm.cs | 131 ++++++++---------- 1 file changed, 61 insertions(+), 70 deletions(-) diff --git a/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs b/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs index 8e9a5eecf..d3b797578 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs @@ -191,14 +191,14 @@ protected override void InternalCompute() ThrowIfCancellationRequested(); // First pass: exploration - ExplorationPass(vertex); + Explore(vertex); // Second pass: coloration - ColorizationPass(vertex); + Colorize(vertex); } } - private void ExplorationPass([NotNull] TVertex vertex) + private void Explore([NotNull] TVertex vertex) { Debug.Assert(vertex != null); @@ -213,7 +213,39 @@ private void ExplorationPass([NotNull] TVertex vertex) } } - private void ColorizationPass([NotNull] TVertex vertex) + [Pure] + private bool Explore(double eps, [NotNull] TVertex vertex, ref int numRoots) + { + Debug.Assert(vertex != null); + + var visited = new Dictionary(); + TVertex current = vertex; + while (NotInTree(current)) + { + if (Chance(eps)) + { + ClearTree(current); + SetInTree(current); + ++numRoots; + if (numRoots > 1) + return false; + } + else + { + if (!TryGetSuccessor(visited, current, out TEdge successor)) + break; + + visited[successor] = 0; + Tree(current, successor); + if (!TryGetNextInTree(current, out current)) + break; + } + } + + return true; + } + + private void Colorize([NotNull] TVertex vertex) { Debug.Assert(vertex != null); @@ -228,6 +260,7 @@ private void ColorizationPass([NotNull] TVertex vertex) #endregion + [Pure] private bool NotInTree([NotNull] TVertex vertex) { return VerticesColors[vertex] == GraphColor.White; @@ -239,6 +272,7 @@ private void SetInTree([NotNull] TVertex vertex) OnFinishVertex(vertex); } + [Pure] private bool TryGetSuccessor([NotNull] IDictionary visited, [NotNull] TVertex vertex, out TEdge successor) { IEnumerable outEdges = VisitedGraph.OutEdges(vertex); @@ -255,6 +289,7 @@ private void Tree([NotNull] TVertex vertex, [NotNull] TEdge next) OnTreeEdge(next); } + [Pure] private bool TryGetNextInTree([NotNull] TVertex vertex, out TVertex next) { if (Successors.TryGetValue(vertex, out TEdge nextEdge)) @@ -267,6 +302,7 @@ private bool TryGetNextInTree([NotNull] TVertex vertex, out TVertex next) return false; } + [Pure] private bool Chance(double eps) { return Rand.NextDouble() <= eps; @@ -278,6 +314,27 @@ private void ClearTree([NotNull] TVertex vertex) OnClearTreeVertex(vertex); } + [Pure] + private bool Attempt(double epsilon) + { + Initialize(); + int numRoots = 0; + + foreach (TVertex vertex in VisitedGraph.Vertices) + { + ThrowIfCancellationRequested(); + + // First pass: exploration + if (!Explore(epsilon, vertex, ref numRoots)) + return false; + + // Second pass: coloration + Colorize(vertex); + } + + return true; + } + /// /// Runs a random tree generation starting at vertex. /// @@ -308,71 +365,5 @@ public void RandomTree() success = Attempt(epsilon); } while (!success); } - - [Pure] - private bool Attempt(double epsilon) - { - Initialize(); - int numRoots = 0; - - foreach (TVertex vertex in VisitedGraph.Vertices) - { - ThrowIfCancellationRequested(); - - // First pass: exploration - if (!Explore(epsilon, vertex, ref numRoots)) - return false; - - // Second pass: coloration - Colorize(vertex); - } - - return true; - } - - [Pure] - private bool Explore(double eps, [NotNull] TVertex vertex, ref int numRoots) - { - Debug.Assert(vertex != null); - - var visited = new Dictionary(); - TVertex current = vertex; - while (NotInTree(current)) - { - if (Chance(eps)) - { - ClearTree(current); - SetInTree(current); - ++numRoots; - if (numRoots > 1) - return false; - } - else - { - if (!TryGetSuccessor(visited, current, out TEdge successor)) - break; - - visited[successor] = 0; - Tree(current, successor); - if (!TryGetNextInTree(current, out current)) - break; - } - } - - return true; - } - - private void Colorize([NotNull] TVertex vertex) - { - Debug.Assert(vertex != null); - - TVertex current = vertex; - while (NotInTree(current)) - { - SetInTree(current); - if (!TryGetNextInTree(current, out current)) - break; - } - } } } \ No newline at end of file From be43081e8e9afb22b0f6410e0e96460adb7e56de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 25 Oct 2021 00:37:08 +0200 Subject: [PATCH 08/39] Add Funding.yml file. --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..b4a246a7c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [KeRNeLith] \ No newline at end of file From 4a32d16d4b579277a4eb14cc3018afd0ca2494ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 24 Oct 2021 16:19:09 +0200 Subject: [PATCH 09/39] Move to langword null for some reference to nullity in documentation comments. --- src/QuikGraph.Graphviz/GraphvizAlgorithm.cs | 2 +- src/QuikGraph.Serialization/XmlWriterExtensions.cs | 2 +- .../Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs | 8 ++++---- .../Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs | 6 +++--- src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs | 4 ++-- .../Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs | 4 ++-- .../HoffmanPavleyRankedShortestPathAlgorithm.cs | 2 +- src/QuikGraph/Algorithms/RootedAlgorithmBase.cs | 2 +- src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs | 2 +- .../ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs | 2 +- src/QuikGraph/Algorithms/TSP/TSP.cs | 2 +- .../TopologicalSort/TopologicalSortAlgorithm.cs | 2 +- src/QuikGraph/Collections/FibonacciQueue.cs | 4 ++-- .../Interfaces/Algorithms/Services/IAlgorithmComponent.cs | 4 ++-- src/QuikGraph/Interfaces/Graphs/IHierarchy.cs | 2 +- .../Interfaces/Graphs/IImplicitUndirectedGraph.cs | 2 +- src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs | 4 ++-- .../Interfaces/Graphs/ITermBidirectionalGraph.cs | 4 ++-- .../Structures/Graphs/DelegateImplicitUndirectedGraph.cs | 2 +- 19 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs b/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs index a6aee85dc..84dd59b5a 100644 --- a/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs +++ b/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs @@ -81,7 +81,7 @@ public IEdgeListGraph VisitedGraph /// /// Dot output stream. /// - /// Not null after a run of or . + /// Not after a run of or . public StringWriter Output { get; private set; } /// diff --git a/src/QuikGraph.Serialization/XmlWriterExtensions.cs b/src/QuikGraph.Serialization/XmlWriterExtensions.cs index 2c7b1c365..02fa83da1 100644 --- a/src/QuikGraph.Serialization/XmlWriterExtensions.cs +++ b/src/QuikGraph.Serialization/XmlWriterExtensions.cs @@ -71,7 +71,7 @@ public static void WriteStringArray([NotNull] XmlWriter xmlWriter, [CanBeNull, I /// /// Writes an array as space separated values. There is a space after every value, even the last one. - /// If array is null, it writes "null". + /// If array is , it writes "null". /// If array is empty, it writes empty string. /// If array is a string array with only one element "null", then it writes "null ". /// diff --git a/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs b/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs index b60d0c345..0104545bb 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/GraphBalancingAlgorithm.cs @@ -153,25 +153,25 @@ public GraphBalancerAlgorithm( /// /// Balancing flow source vertex. /// - /// Not null if the algorithm has been run (and not reverted). + /// Not if the algorithm has been run (and not reverted). public TVertex BalancingSource { get; private set; } /// /// Balancing source edge (between and ). /// - /// Not null if the algorithm has been run (and not reverted). + /// Not if the algorithm has been run (and not reverted). public TEdge BalancingSourceEdge { get; private set; } /// /// Balancing flow sink vertex. /// - /// Not null if the algorithm has been run (and not reverted). + /// Not if the algorithm has been run (and not reverted). public TVertex BalancingSink { get; private set; } /// /// Balancing sink edge (between and ). /// - /// Not null if the algorithm has been run (and not reverted). + /// Not if the algorithm has been run (and not reverted). public TEdge BalancingSinkEdge { get; private set; } [NotNull, ItemNotNull] diff --git a/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs b/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs index c123fbf70..6d4a6cfb6 100644 --- a/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/MaximumFlow/MaximumFlowAlgorithmBase.cs @@ -65,19 +65,19 @@ protected MaximumFlowAlgorithm( /// /// Graph reversed edges. /// - /// Should be not null but may be empty. + /// Should be not but may be empty. public IDictionary ReversedEdges { get; protected set; } /// /// Flow source vertex. /// - /// Must not be null to run the algorithm. + /// Must not be to run the algorithm. public TVertex Source { get; set; } /// /// Flow sink vertex. /// - /// Must not be null to run the algorithm. + /// Must not be to run the algorithm. public TVertex Sink { get; set; } /// diff --git a/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs b/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs index 2185c03dd..4bd97fdad 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/IEdgeChain.cs @@ -16,7 +16,7 @@ public interface IEdgeChain /// /// The graph to search in. /// The vertex. - /// Found successor, otherwise null. + /// Found successor, otherwise . /// True if a successor was found, false otherwise. /// is . /// is . @@ -29,7 +29,7 @@ public interface IEdgeChain /// /// Edge set in which searching. /// The vertex. - /// Found successor, otherwise null. + /// Found successor, otherwise . /// True if a successor was found, false otherwise. /// is . /// is . diff --git a/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs b/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs index 389ad984a..fba7df0b2 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/WeightedMarkovEdgeChainBase.cs @@ -58,7 +58,7 @@ protected double GetWeights([NotNull, ItemNotNull] IEnumerable edges) /// The graph to search in. /// The vertex. /// The position. - /// Found successor, otherwise null. + /// Found successor, otherwise . /// True if a successor was found, false otherwise. protected bool TryGetSuccessor([NotNull] IImplicitGraph graph, [NotNull] TVertex vertex, double position, out TEdge successor) { @@ -74,7 +74,7 @@ protected bool TryGetSuccessor([NotNull] IImplicitGraph graph, [ /// /// Edge set in which searching. /// The position. - /// Found successor, otherwise null. + /// Found successor, otherwise . /// True if a successor was found, false otherwise. protected bool TryGetSuccessor([NotNull, ItemNotNull] IEnumerable edges, double position, out TEdge successor) { diff --git a/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs index bd1730d27..2187e8400 100644 --- a/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/RankedShortestPath/HoffmanPavleyRankedShortestPathAlgorithm.cs @@ -98,7 +98,7 @@ public void SetTargetVertex([NotNull] TVertex target) /// /// Tries to get the target vertex if set. /// - /// Target vertex if set, otherwise null. + /// Target vertex if set, otherwise . /// True if the target vertex was set, false otherwise. [Pure] [ContractAnnotation("=> true, target:notnull;=> false, target:null")] diff --git a/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs b/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs index 430692034..a7b0c8689 100644 --- a/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/RootedAlgorithmBase.cs @@ -42,7 +42,7 @@ protected RootedAlgorithmBase( /// /// Tries to get the root vertex if set. /// - /// Root vertex if set, otherwise null. + /// Root vertex if set, otherwise . /// True if the root vertex was set, false otherwise. [Pure] [ContractAnnotation("=> true, root:notnull;=> false, root:null")] diff --git a/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs b/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs index 0afc1d602..6bed50cb3 100644 --- a/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs +++ b/src/QuikGraph/Algorithms/RootedSearchAlgorithmBase.cs @@ -39,7 +39,7 @@ protected RootedSearchAlgorithmBase( /// /// Tries to get the target vertex if set. /// - /// Target vertex if set, otherwise null. + /// Target vertex if set, otherwise . /// True if the target vertex was set, false otherwise. [Pure] [ContractAnnotation("=> true, target:notnull;=> false, target:null")] diff --git a/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs b/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs index 3d3f0357d..07dd52aa9 100644 --- a/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs +++ b/src/QuikGraph/Algorithms/ShortestPath/FloydWarshallAllShortestPathAlgorithm.cs @@ -162,7 +162,7 @@ public bool TryGetDistance([NotNull] TVertex source, [NotNull] TVertex target, o /// /// Source vertex. /// Target vertex. - /// The found path, otherwise null. + /// The found path, otherwise . /// True if a path linking both vertices was found, false otherwise. /// is . /// is . diff --git a/src/QuikGraph/Algorithms/TSP/TSP.cs b/src/QuikGraph/Algorithms/TSP/TSP.cs index 8bf39ed0a..d3417992c 100644 --- a/src/QuikGraph/Algorithms/TSP/TSP.cs +++ b/src/QuikGraph/Algorithms/TSP/TSP.cs @@ -21,7 +21,7 @@ public class TSP : ShortestPathAlgorithmBase _taskManager = new TasksManager(); /// - /// Shortest path found, otherwise null. + /// Shortest path found, otherwise . /// [CanBeNull] public BidirectionalGraph ResultPath { get; private set; } diff --git a/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs b/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs index 7a34a9448..be13533e5 100644 --- a/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TopologicalSort/TopologicalSortAlgorithm.cs @@ -36,7 +36,7 @@ public TopologicalSortAlgorithm( /// /// Sorted vertices. /// - /// It is null if the algorithm has not been run yet. + /// It is if the algorithm has not been run yet. [ItemNotNull] public TVertex[] SortedVertices { get; private set; } diff --git a/src/QuikGraph/Collections/FibonacciQueue.cs b/src/QuikGraph/Collections/FibonacciQueue.cs index 0a5fd93a5..014ee6ce2 100644 --- a/src/QuikGraph/Collections/FibonacciQueue.cs +++ b/src/QuikGraph/Collections/FibonacciQueue.cs @@ -41,7 +41,7 @@ public FibonacciQueue([NotNull] Func distanceFunc) /// Initializes a new instance of the class. /// /// Initial capacity. - /// Set of vertices (null if is 0). + /// Set of vertices ( if is 0). /// Function that compute the distance for a given vertex. /// is . /// is negative. @@ -57,7 +57,7 @@ public FibonacciQueue( /// Initializes a new instance of the class. /// /// Initial capacity. - /// Set of vertices (null if is 0). + /// Set of vertices ( if is 0). /// Function that compute the distance for a given vertex. /// Comparer of distances. /// is . diff --git a/src/QuikGraph/Interfaces/Algorithms/Services/IAlgorithmComponent.cs b/src/QuikGraph/Interfaces/Algorithms/Services/IAlgorithmComponent.cs index 832aa18e6..7f27f0e18 100644 --- a/src/QuikGraph/Interfaces/Algorithms/Services/IAlgorithmComponent.cs +++ b/src/QuikGraph/Interfaces/Algorithms/Services/IAlgorithmComponent.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using JetBrains.Annotations; namespace QuikGraph.Algorithms.Services { @@ -17,7 +17,7 @@ public interface IAlgorithmComponent /// Gets the service with given . /// /// Service type. - /// Found service, otherwise null. + /// Found service, otherwise . [Pure] [CanBeNull] T GetService(); diff --git a/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs b/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs index 2893039c5..c5b98dfcc 100644 --- a/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs +++ b/src/QuikGraph/Interfaces/Graphs/IHierarchy.cs @@ -21,7 +21,7 @@ public interface IHierarchy : IMutableVertexAndEdgeListGraph. /// /// The vertex. - /// The parent vertex if there is one, otherwise null. + /// The parent vertex if there is one, otherwise . /// is . /// The given is the root of the graph. [Pure] diff --git a/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs b/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs index 9478a489d..75cd35356 100644 --- a/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IImplicitUndirectedGraph.cs @@ -68,7 +68,7 @@ public interface IImplicitUndirectedGraph : IImplicitVertexSet /// Source vertex. /// Target vertex. - /// Edge found, otherwise null. + /// Edge found, otherwise . /// True if an edge was found, false otherwise. /// is . /// is . diff --git a/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs b/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs index a977fbf07..264f3f062 100644 --- a/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/IIncidenceGraph.cs @@ -30,7 +30,7 @@ public interface IIncidenceGraph : IImplicitGraph /// Source vertex. /// Target vertex. - /// Edge found, otherwise null. + /// Edge found, otherwise . /// True if an edge was found, false otherwise. /// is . /// is . @@ -44,7 +44,7 @@ public interface IIncidenceGraph : IImplicitGraph /// Source vertex. /// Target vertex. - /// Edges found, otherwise null. + /// Edges found, otherwise . /// True if at least an edge was found, false otherwise. /// is . /// is . diff --git a/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs b/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs index 8ee723d88..a0a0e2b69 100644 --- a/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs +++ b/src/QuikGraph/Interfaces/Graphs/ITermBidirectionalGraph.cs @@ -62,7 +62,7 @@ public interface ITermBidirectionalGraph : IBidirectionalGraph /// The vertex. /// Out terminal index. - /// Out-edges found, otherwise null. + /// Out-edges found, otherwise . /// True if was found or/and out-edges were found, false otherwise. /// is . [Pure] @@ -118,7 +118,7 @@ public interface ITermBidirectionalGraph : IBidirectionalGraph /// The vertex. /// Out terminal index. - /// In-edges found, otherwise null. + /// In-edges found, otherwise . /// True if was found or/and in-edges were found, false otherwise. /// is . [Pure] diff --git a/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs b/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs index c02c2a055..96bd2f04e 100644 --- a/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs +++ b/src/QuikGraph/Structures/Graphs/DelegateImplicitUndirectedGraph.cs @@ -140,7 +140,7 @@ internal virtual bool TryGetAdjacentEdgesInternal([NotNull] TVertex vertex, out /// Tries to get adjacent edges of the given . /// /// The vertex. - /// Edges found, otherwise null. + /// Edges found, otherwise . /// True if was found or/and edges were found, false otherwise. /// is . [Pure] From 59cf3a671ab0200c6e07570f91bff0fc401db9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 25 Oct 2021 00:20:21 +0200 Subject: [PATCH 10/39] Rename tests files for consistency. --- ...{SystemSerializationTests.cs => BinarySerializationTests.cs} | 2 +- .../{GraphMLSerializerTests.cs => GraphMLSerializationTests.cs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/QuikGraph.Serialization.Tests/{SystemSerializationTests.cs => BinarySerializationTests.cs} (99%) rename tests/QuikGraph.Serialization.Tests/{GraphMLSerializerTests.cs => GraphMLSerializationTests.cs} (100%) diff --git a/tests/QuikGraph.Serialization.Tests/SystemSerializationTests.cs b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs similarity index 99% rename from tests/QuikGraph.Serialization.Tests/SystemSerializationTests.cs rename to tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs index ec57230f8..08cedd408 100644 --- a/tests/QuikGraph.Serialization.Tests/SystemSerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using JetBrains.Annotations; diff --git a/tests/QuikGraph.Serialization.Tests/GraphMLSerializerTests.cs b/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs similarity index 100% rename from tests/QuikGraph.Serialization.Tests/GraphMLSerializerTests.cs rename to tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs From 9b174aa9c596e7d60cecb6fe91c0d178b6569c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 25 Oct 2021 00:21:08 +0200 Subject: [PATCH 11/39] Add tests for Xml graph serialization. --- .../BinarySerializationTests.cs | 200 +----------- .../Helpers/LambdaEqualityComparer.cs | 47 +++ .../SerializationTestCaseSources.cs | 194 ++++++++++++ .../XmlSerializationTests.cs | 297 +++++++++++++++--- 4 files changed, 501 insertions(+), 237 deletions(-) create mode 100644 tests/QuikGraph.Serialization.Tests/Helpers/LambdaEqualityComparer.cs create mode 100644 tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs diff --git a/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs index 08cedd408..89cf2e64a 100644 --- a/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs @@ -1,8 +1,8 @@ using System; -using System.Collections.Generic; using System.IO; using JetBrains.Annotations; using NUnit.Framework; +using static QuikGraph.Serialization.Tests.SerializationTestCaseSources; namespace QuikGraph.Serialization.Tests { @@ -40,30 +40,7 @@ private static TGraph SerializeDeserialize([NotNull] TGr #endregion - [NotNull, ItemNotNull] - private static IEnumerable BinarySerializationAdjacencyGraphTestCases - { - [UsedImplicitly] - get - { - var emptyGraph = new AdjacencyGraph>(); - yield return new TestCaseData(emptyGraph); - - var graph = new AdjacencyGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(2, 1), - new EquatableEdge(2, 2) - }); - yield return new TestCaseData(graph); - } - } - - [TestCaseSource(nameof(BinarySerializationAdjacencyGraphTestCases))] + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] public void BinarySerialization_AdjacencyGraph([NotNull] AdjacencyGraph> graph) { AdjacencyGraph> deserializedGraph1 = @@ -76,7 +53,7 @@ public void BinarySerialization_AdjacencyGraph([NotNull] AdjacencyGraph> graph) { var bidirectionalAdapterGraph = new BidirectionalAdapterGraph>(graph); @@ -85,47 +62,7 @@ public void BinarySerialization_AdapterGraph([NotNull] AdjacencyGraph BinarySerializationClusteredAdjacencyGraphTestCases - { - [UsedImplicitly] - get - { - var emptyGraph = new AdjacencyGraph>(); - var clusterEmptyGraph = new ClusteredAdjacencyGraph>(emptyGraph); - yield return new TestCaseData(clusterEmptyGraph); - - var graph = new AdjacencyGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(2, 1), - new EquatableEdge(2, 2) - }); - var clusterGraph = new ClusteredAdjacencyGraph>(graph); - yield return new TestCaseData(clusterGraph); - - graph = new AdjacencyGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(3, 2) - }); - clusterGraph = new ClusteredAdjacencyGraph>(graph); - ClusteredAdjacencyGraph> subGraph = clusterGraph.AddCluster(); - subGraph.AddVertexRange(new[] { 4, 5, 6 }); - subGraph.AddEdge(new EquatableEdge(4, 6)); - yield return new TestCaseData(clusterGraph); - } - } - - [TestCaseSource(nameof(BinarySerializationClusteredAdjacencyGraphTestCases))] + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphTestCases))] public void BinarySerialization_ClusteredGraph([NotNull] ClusteredAdjacencyGraph> graph) { ClusteredAdjacencyGraph> deserializedGraph = @@ -133,32 +70,7 @@ public void BinarySerialization_ClusteredGraph([NotNull] ClusteredAdjacencyGraph Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } - [NotNull, ItemNotNull] - private static IEnumerable BinarySerializationCompressedGraphTestCases - { - [UsedImplicitly] - get - { - var emptyGraph = new AdjacencyGraph>(); - var emptyCompressedGraph = CompressedSparseRowGraph.FromGraph(emptyGraph); - yield return new TestCaseData(emptyCompressedGraph); - - var graph = new AdjacencyGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(2, 1), - new EquatableEdge(2, 2) - }); - var compressedGraph = CompressedSparseRowGraph.FromGraph(emptyGraph); - yield return new TestCaseData(compressedGraph); - } - } - - [TestCaseSource(nameof(BinarySerializationCompressedGraphTestCases))] + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphTestCases))] public void BinarySerialization_CompressedGraph([NotNull] CompressedSparseRowGraph graph) { CompressedSparseRowGraph deserializedGraph = @@ -166,31 +78,7 @@ public void BinarySerialization_CompressedGraph([NotNull] CompressedSparseRowGra Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } - [NotNull, ItemNotNull] - private static IEnumerable BinarySerializationBidirectionalGraphTestCases - { - [UsedImplicitly] - get - { - var emptyGraph = new BidirectionalGraph>(); - yield return new TestCaseData(emptyGraph); - - var graph = new BidirectionalGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(2, 1), - new EquatableEdge(2, 2) - }); - - yield return new TestCaseData(graph); - } - } - - [TestCaseSource(nameof(BinarySerializationBidirectionalGraphTestCases))] + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphTestCases))] public void BinarySerialization_BidirectionalGraph([NotNull] BidirectionalGraph> graph) { BidirectionalGraph> deserializedGraph = @@ -213,30 +101,7 @@ public void BinarySerialization_BidirectionalGraph([NotNull] BidirectionalGraph< Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); } - [NotNull, ItemNotNull] - private static IEnumerable BinarySerializationBidirectionalMatrixGraphTestCases - { - [UsedImplicitly] - get - { - var emptyGraph = new BidirectionalMatrixGraph>(10); - yield return new TestCaseData(emptyGraph); - - var graph = new BidirectionalMatrixGraph>(4); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(2, 1), - new EquatableEdge(2, 2) - }); - - yield return new TestCaseData(graph); - } - } - - [TestCaseSource(nameof(BinarySerializationBidirectionalMatrixGraphTestCases))] + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalMatrixGraphTestCases))] public void BinarySerialization_BidirectionalMatrixGraph([NotNull] BidirectionalMatrixGraph> graph) { BidirectionalMatrixGraph> deserializedGraph = @@ -244,31 +109,7 @@ public void BinarySerialization_BidirectionalMatrixGraph([NotNull] Bidirectional Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } - [NotNull, ItemNotNull] - private static IEnumerable BinarySerializationUndirectedGraphTestCases - { - [UsedImplicitly] - get - { - var emptyGraph = new UndirectedGraph>(); - yield return new TestCaseData(emptyGraph); - - var graph = new UndirectedGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(2, 1), - new EquatableEdge(2, 2) - }); - - yield return new TestCaseData(graph); - } - } - - [TestCaseSource(nameof(BinarySerializationUndirectedGraphTestCases))] + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphTestCases))] public void BinarySerialization_UndirectedGraph([NotNull] UndirectedGraph> graph) { UndirectedGraph> deserializedGraph1 = @@ -281,30 +122,7 @@ public void BinarySerialization_UndirectedGraph([NotNull] UndirectedGraph BinarySerializationEdgeListGraphTestCases - { - [UsedImplicitly] - get - { - var emptyGraph = new EdgeListGraph>(); - yield return new TestCaseData(emptyGraph); - - var graph = new EdgeListGraph>(); - graph.AddEdgeRange(new[] - { - new EquatableEdge(0, 1), - new EquatableEdge(1, 2), - new EquatableEdge(2, 0), - new EquatableEdge(2, 1), - new EquatableEdge(2, 2) - }); - - yield return new TestCaseData(graph); - } - } - - [TestCaseSource(nameof(BinarySerializationEdgeListGraphTestCases))] + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphTestCases))] public void BinarySerialization_EdgeListGraph([NotNull] EdgeListGraph> graph) { EdgeListGraph> deserializedGraph = diff --git a/tests/QuikGraph.Serialization.Tests/Helpers/LambdaEqualityComparer.cs b/tests/QuikGraph.Serialization.Tests/Helpers/LambdaEqualityComparer.cs new file mode 100644 index 000000000..8148d9eda --- /dev/null +++ b/tests/QuikGraph.Serialization.Tests/Helpers/LambdaEqualityComparer.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace QuikGraph.Serialization.Tests +{ + /// + /// that can be constructed from lambdas. + /// + /// Element to compare type. + internal sealed class LambdaEqualityComparer : IEqualityComparer + { + [NotNull] + private readonly Func _comparer; + + [NotNull] + private readonly Func _hashGenerator; + + private LambdaEqualityComparer([NotNull] Func comparer, [NotNull] Func hash) + { + _comparer = comparer; + _hashGenerator = hash; + } + + /// + public bool Equals(T x, T y) + { + return _comparer(x, y); + } + + /// + public int GetHashCode(T value) + { + return _hashGenerator(value); + } + + /// + /// Creates from given and lambdas. + /// + [Pure] + [NotNull] + public static IEqualityComparer Create([NotNull] Func comparer, [NotNull] Func hash) + { + return new LambdaEqualityComparer(comparer, hash); + } + } +} \ No newline at end of file diff --git a/tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs b/tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs new file mode 100644 index 000000000..553fe222a --- /dev/null +++ b/tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs @@ -0,0 +1,194 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using NUnit.Framework; + +namespace QuikGraph.Serialization.Tests +{ + /// + /// Test case sources for serialization tests. + /// + internal static class SerializationTestCaseSources + { + [NotNull, ItemNotNull] + public static IEnumerable SerializationAdjacencyGraphTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph>(); + yield return new TestCaseData(emptyGraph); + + var graph = new AdjacencyGraph>(); + graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(2, 1), + new EquatableEdge(2, 2) + }); + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationClusteredAdjacencyGraphTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph>(); + var clusterEmptyGraph = new ClusteredAdjacencyGraph>(emptyGraph); + yield return new TestCaseData(clusterEmptyGraph); + + var graph = new AdjacencyGraph>(); + graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(2, 1), + new EquatableEdge(2, 2) + }); + var clusterGraph = new ClusteredAdjacencyGraph>(graph); + yield return new TestCaseData(clusterGraph); + + graph = new AdjacencyGraph>(); + graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(3, 2) + }); + clusterGraph = new ClusteredAdjacencyGraph>(graph); + ClusteredAdjacencyGraph> subGraph = clusterGraph.AddCluster(); + subGraph.AddVertexRange(new[] { 4, 5, 6 }); + subGraph.AddEdge(new EquatableEdge(4, 6)); + yield return new TestCaseData(clusterGraph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationCompressedGraphTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph>(); + var emptyCompressedGraph = CompressedSparseRowGraph.FromGraph(emptyGraph); + yield return new TestCaseData(emptyCompressedGraph); + + var graph = new AdjacencyGraph>(); + graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(2, 1), + new EquatableEdge(2, 2) + }); + var compressedGraph = CompressedSparseRowGraph.FromGraph(emptyGraph); + yield return new TestCaseData(compressedGraph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationBidirectionalGraphTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new BidirectionalGraph>(); + yield return new TestCaseData(emptyGraph); + + var graph = new BidirectionalGraph>(); + graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(2, 1), + new EquatableEdge(2, 2) + }); + + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationBidirectionalMatrixGraphTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new BidirectionalMatrixGraph>(10); + yield return new TestCaseData(emptyGraph); + + var graph = new BidirectionalMatrixGraph>(4); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(2, 1), + new EquatableEdge(2, 2) + }); + + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationUndirectedGraphTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new UndirectedGraph>(); + yield return new TestCaseData(emptyGraph); + + var graph = new UndirectedGraph>(); + graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(2, 1), + new EquatableEdge(2, 2) + }); + + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationEdgeListGraphTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new EdgeListGraph>(); + yield return new TestCaseData(emptyGraph); + + var graph = new EdgeListGraph>(); + graph.AddEdgeRange(new[] + { + new EquatableEdge(0, 1), + new EquatableEdge(1, 2), + new EquatableEdge(2, 0), + new EquatableEdge(2, 1), + new EquatableEdge(2, 2) + }); + + yield return new TestCaseData(graph); + } + } + } +} \ No newline at end of file diff --git a/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs b/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs index bee5329ba..576e74fb0 100644 --- a/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Xml; using System.Xml.XPath; @@ -9,6 +10,7 @@ using QuikGraph.Algorithms; using static QuikGraph.Tests.GraphTestHelpers; using static QuikGraph.Tests.QuikGraphUnitTestsHelpers; +using static QuikGraph.Serialization.Tests.SerializationTestCaseSources; namespace QuikGraph.Serialization.Tests { @@ -43,25 +45,18 @@ private static void SerializeAndRead( { var settings = new XmlWriterSettings { Indent = true, IndentChars = Indent }; using (var memory = new MemoryStream()) + using (var writer = new StreamWriter(memory)) { - var writer = new StreamWriter(memory); - try + using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings)) { - using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings)) - { - onSerialize(xmlWriter); - } + onSerialize(xmlWriter); + } - memory.Position = 0; + memory.Position = 0; - using (var reader = new StreamReader(memory)) - { - checkSerializedContent(reader.ReadToEnd()); - } - } - finally + using (var reader = new StreamReader(memory)) { - writer.Dispose(); + checkSerializedContent(reader.ReadToEnd()); } } } @@ -106,7 +101,6 @@ private static IEnumerable XmlSerializationGraphTestCases public void SerializeToXml([NotNull] TGraph graph) where TGraph: IMutableVertexAndEdgeSet> { - var persons = new List(); var jacob = new Person("Jacob", "Hochstetler") { BirthDate = new DateTime(1712, 01, 01), @@ -115,7 +109,6 @@ public void SerializeToXml([NotNull] TGraph graph) DeathPlace = "Pennsylvania, USA", Gender = Gender.Male }; - persons.Add(jacob); var john = new Person("John", "Hochstetler") { @@ -125,7 +118,6 @@ public void SerializeToXml([NotNull] TGraph graph) DeathPlace = "Summit Mills, PA", Gender = Gender.Male }; - persons.Add(john); var jonathon = new Person("Jonathon", "Hochstetler") { @@ -133,7 +125,6 @@ public void SerializeToXml([NotNull] TGraph graph) DeathDate = new DateTime(1823, 05, 08), Gender = Gender.Male }; - persons.Add(jonathon); var emanuel = new Person("Emanuel", "Hochstedler") { @@ -141,19 +132,14 @@ public void SerializeToXml([NotNull] TGraph graph) DeathDate = new DateTime(1900, 01, 01), Gender = Gender.Male }; - persons.Add(emanuel); - var relations = new List> - { - new TaggedEdge(jacob, john, jacob.ChildRelationshipText), - new TaggedEdge(john, jonathon, john.ChildRelationshipText), - new TaggedEdge(jonathon, emanuel, jonathon.ChildRelationshipText) - }; - - foreach (TaggedEdge relation in relations) - { - graph.AddVerticesAndEdge(relation); - } + graph.AddVerticesAndEdgeRange( + new TaggedEdge[] + { + new(jacob, john, jacob.ChildRelationshipText), + new(john, jonathon, john.ChildRelationshipText), + new(jonathon, emanuel, jonathon.ChildRelationshipText) + }); SerializeAndRead( writer => graph.SerializeToXml( @@ -164,27 +150,36 @@ public void SerializeToXml([NotNull] TGraph graph) VertexNodeName, EdgeNodeName, ""), - content => + content => CheckXmlGraphSerialization(graph, content)); + + #region Local function + + static void CheckXmlGraphSerialization( + [NotNull] IEdgeListGraph> graph, + [NotNull] string xmlGraph) + { + var expectedSerializedGraph = new StringBuilder($"{XmlHeader}{Environment.NewLine}"); + expectedSerializedGraph.AppendLine($"<{GraphNodeName}>"); + + foreach (Person person in graph.Vertices) { - var expectedSerializedGraph = new StringBuilder($"{XmlHeader}{Environment.NewLine}"); - expectedSerializedGraph.AppendLine($"<{GraphNodeName}>"); + expectedSerializedGraph.AppendLine($"{Indent}<{VertexNodeName} id=\"{person.Id}\" />"); + } - foreach (Person person in persons) - { - expectedSerializedGraph.AppendLine($"{Indent}<{VertexNodeName} id=\"{person.Id}\" />"); - } + TaggedEdge[] relations = graph.Edges.ToArray(); + for (int i = 0; i < relations.Length; ++i) + { + expectedSerializedGraph.AppendLine($"{Indent}<{EdgeNodeName} id=\"{i}\" source=\"{relations[i].Source.Id}\" target=\"{relations[i].Target.Id}\" />"); + } - for (int i = 0 ; i < relations.Count ; ++i) - { - expectedSerializedGraph.AppendLine($"{Indent}<{EdgeNodeName} id=\"{i}\" source=\"{relations[i].Source.Id}\" target=\"{relations[i].Target.Id}\" />"); - } + expectedSerializedGraph.Append($""); - expectedSerializedGraph.Append($""); + StringAssert.AreEqualIgnoringCase( + expectedSerializedGraph.ToString(), + xmlGraph); + } - StringAssert.AreEqualIgnoringCase( - expectedSerializedGraph.ToString(), - content); - }); + #endregion } [Test] @@ -874,5 +869,215 @@ public void DeserializeFromXml_Reader_Throws() } #endregion + + #region Serialization/Deserialization + + #region Test Helpers + + [Pure] + private static int DeserializeVertex([NotNull] XmlReader reader) + { + return int.Parse(reader.GetAttribute("id", "") ?? throw new AssertionException("Unable to deserialize vertex.")); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize( + [NotNull] TInGraph graph, + [NotNull, InstantHandle] Func deserialize) + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph + { + Assert.IsNotNull(graph); + + var settings = new XmlWriterSettings { Indent = true, IndentChars = Indent }; + using (var memory = new MemoryStream()) + using (var writer = new StreamWriter(memory)) + { + // Serialize + using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings)) + { + graph.SerializeToXml( + xmlWriter, + vertex => vertex.ToString(), + graph.GetEdgeIdentity(), + "graph", + "node", + "edge", + ""); + } + + memory.Position = 0; + + // Deserialize + using (XmlReader xmlReader = XmlReader.Create(memory)) + { + TOutGraph deserializedGraph = deserialize(xmlReader); + Assert.IsNotNull(deserializedGraph); + Assert.AreNotSame(graph, deserializedGraph); + return deserializedGraph; + } + } + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + return SerializeDeserialize, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + reader.DeserializeFromXml( + "graph", + "node", + "edge", + "", + _ => new TOutGraph(), + DeserializeVertex, + nav => new EquatableEdge( + int.Parse(nav.GetAttribute("source", "") ?? throw new AssertionException("Unable to deserialize edge source.")), + int.Parse(nav.GetAttribute("target", "") ?? throw new AssertionException("Unable to deserialize edge target."))))); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_SEdge([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + return SerializeDeserialize, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => + reader.DeserializeFromXml( + "graph", + "node", + "edge", + "", + _ => new TOutGraph(), + DeserializeVertex, + nav => new SEquatableEdge( + int.Parse(nav.GetAttribute("source", "") ?? throw new AssertionException("Unable to deserialize edge source.")), + int.Parse(nav.GetAttribute("target", "") ?? throw new AssertionException("Unable to deserialize edge target."))))); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Reversed([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph>> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + return SerializeDeserialize>, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + reader.DeserializeFromXml( + "graph", + "node", + "edge", + "", + _ => new TOutGraph(), + DeserializeVertex, + nav => new EquatableEdge( + int.Parse(nav.GetAttribute("source", "") ?? throw new AssertionException("Unable to deserialize edge source.")), + int.Parse(nav.GetAttribute("target", "") ?? throw new AssertionException("Unable to deserialize edge target."))))); + } + + #endregion + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] + public void XmlSerialization_AdjacencyGraph([NotNull] AdjacencyGraph> graph) + { + AdjacencyGraph> deserializedGraph1 = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayAdjacencyGraph>(graph); + AdjacencyGraph> deserializedGraph2 = + SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] + public void XmlSerialization_AdapterGraph([NotNull] AdjacencyGraph> graph) + { + var bidirectionalAdapterGraph = new BidirectionalAdapterGraph>(graph); + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(bidirectionalAdapterGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphTestCases))] + public void XmlSerialization_ClusteredGraph([NotNull] ClusteredAdjacencyGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphTestCases))] + public void XmlSerialization_CompressedGraph([NotNull] CompressedSparseRowGraph graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize_SEdge, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphTestCases))] + public void XmlSerialization_BidirectionalGraph([NotNull] BidirectionalGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + + var arrayGraph = new ArrayBidirectionalGraph>(graph); + AdjacencyGraph> deserializedGraph2 = + SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + + var reversedGraph = new ReversedBidirectionalGraph>(graph); + BidirectionalGraph> deserializedGraph3 = + SerializeDeserialize_Reversed>, BidirectionalGraph>>(reversedGraph); + Assert.IsTrue( + EquateGraphs.Equate( + graph, + deserializedGraph3, + EqualityComparer.Default, + LambdaEqualityComparer>.Create( + (edge1, edge2) => Equals(edge1.Source, edge2.Target) && Equals(edge1.Target, edge2.Source), + edge => edge.GetHashCode()))); + + var undirectedBidirectionalGraph = new UndirectedBidirectionalGraph>(graph); + UndirectedGraph> deserializedGraph4 = + SerializeDeserialize>, UndirectedGraph>>(undirectedBidirectionalGraph); + Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalMatrixGraphTestCases))] + public void XmlSerialization_BidirectionalMatrixGraph([NotNull] BidirectionalMatrixGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphTestCases))] + public void XmlSerialization_UndirectedGraph([NotNull] UndirectedGraph> graph) + { + UndirectedGraph> deserializedGraph1 = + SerializeDeserialize>, UndirectedGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayUndirectedGraph>(graph); + UndirectedGraph> deserializedGraph2 = + SerializeDeserialize>, UndirectedGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphTestCases))] + public void XmlSerialization_EdgeListGraph([NotNull] EdgeListGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + #endregion } } \ No newline at end of file From 24a34bc15b28eddf24dcd073f6dc17953a0b82c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Wed, 27 Oct 2021 00:44:25 +0200 Subject: [PATCH 12/39] Documentation use library logo. --- docs/docfx.json | 5 + docs/images/favicon.ico | Bin 0 -> 146181 bytes docs/images/logo.svg | 312 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 docs/images/favicon.ico create mode 100644 docs/images/logo.svg diff --git a/docs/docfx.json b/docs/docfx.json index 50ca85df8..7af7d5925 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -69,6 +69,11 @@ } ], "dest": "_site", + "globalMetadata": { + "_appFaviconPath": "images/favicon.ico", + "_appLogoPath": "images/logo.svg", + "_appFooter": "QuikGraph" + }, "globalMetadataFiles": [], "fileMetadataFiles": [], "template": [ "default", "templates/material" ], diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7eea722404e022e9397152a4f418eeb80df48da9 GIT binary patch literal 146181 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

GwR6zKDO4Yq{QM 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

#Dp47ZXiNhuNylhU9 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 Kzn8D!YyS_{#n_qv literal 0 HcmV?d00001 diff --git a/docs/images/logo.svg b/docs/images/logo.svg new file mode 100644 index 000000000..9898c5f5a --- /dev/null +++ b/docs/images/logo.svg @@ -0,0 +1,312 @@ + + + + From 684919bb1de7112919873d83b184813803f5f19c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 31 Oct 2021 01:15:37 +0200 Subject: [PATCH 13/39] GraphML deserialization use IMutableVertexAndEdgeSet rather than IMutableVertexAndEdgeListGraph. This allow to use GraphML serialization extensions on undirected graphs. --- src/QuikGraph.Serialization/GraphMLExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/QuikGraph.Serialization/GraphMLExtensions.cs b/src/QuikGraph.Serialization/GraphMLExtensions.cs index 3b943205b..e912e3345 100644 --- a/src/QuikGraph.Serialization/GraphMLExtensions.cs +++ b/src/QuikGraph.Serialization/GraphMLExtensions.cs @@ -168,7 +168,7 @@ public static void DeserializeFromGraphML( [NotNull] IdentifiableVertexFactory vertexFactory, [NotNull] IdentifiableEdgeFactory edgeFactory) where TEdge : IEdge - where TGraph : IMutableVertexAndEdgeListGraph + where TGraph : IMutableVertexAndEdgeSet { var serializer = new GraphMLDeserializer(); serializer.Deserialize(reader, graph, vertexFactory, edgeFactory); @@ -198,7 +198,7 @@ public static void DeserializeFromGraphML( [NotNull] IdentifiableVertexFactory vertexFactory, [NotNull] IdentifiableEdgeFactory edgeFactory) where TEdge : IEdge - where TGraph : IMutableVertexAndEdgeListGraph + where TGraph : IMutableVertexAndEdgeSet { if (reader is null) throw new ArgumentNullException(nameof(reader)); @@ -247,7 +247,7 @@ public static void DeserializeFromGraphML( [NotNull] IdentifiableVertexFactory vertexFactory, [NotNull] IdentifiableEdgeFactory edgeFactory) where TEdge : IEdge - where TGraph : IMutableVertexAndEdgeListGraph + where TGraph : IMutableVertexAndEdgeSet { if (string.IsNullOrEmpty(filePath)) throw new ArgumentException("Must provide a file path.", nameof(filePath)); @@ -284,7 +284,7 @@ public static void DeserializeAndValidateFromGraphML( [NotNull] IdentifiableVertexFactory vertexFactory, [NotNull] IdentifiableEdgeFactory edgeFactory) where TEdge : IEdge - where TGraph : IMutableVertexAndEdgeListGraph + where TGraph : IMutableVertexAndEdgeSet { if (reader is null) throw new ArgumentNullException(nameof(reader)); From 3d367fc678fa03cd579827b5f4036647eee97009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 31 Oct 2021 01:09:08 +0200 Subject: [PATCH 14/39] Add tests for GraphML serialization. --- .../GraphMLSerializationTests.cs | 209 +++++++++++++++++- 1 file changed, 200 insertions(+), 9 deletions(-) diff --git a/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs b/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs index 0d2fa0c7c..91ca0d183 100644 --- a/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs @@ -10,7 +10,9 @@ using System.Xml.XPath; using JetBrains.Annotations; using NUnit.Framework; +using QuikGraph.Algorithms; using QuikGraph.Tests; +using static QuikGraph.Serialization.Tests.SerializationTestCaseSources; using static QuikGraph.Tests.QuikGraphUnitTestsHelpers; namespace QuikGraph.Serialization.Tests @@ -30,17 +32,17 @@ private static TGraph VerifySerialization( [NotNull, InstantHandle] Func serializeGraph, [NotNull, InstantHandle] Func deserializeGraph) { - // Serialize the graph to XML - string xml = serializeGraph(graph); + // Serialize the graph to GraphML + string graphml = serializeGraph(graph); // Deserialize a graph from previous serialization - TGraph serializedGraph = deserializeGraph(xml); + TGraph serializedGraph = deserializeGraph(graphml); // Serialize the deserialized graph - string newXml = serializeGraph(serializedGraph); + string newGraphml = serializeGraph(serializedGraph); // => Serialization should produce the same result - Assert.AreEqual(xml, newXml); + Assert.AreEqual(graphml, newGraphml); Assert.AreNotSame(graph, serializeGraph); @@ -122,9 +124,9 @@ public void GraphMLSerialization_HeaderCheck(bool emitDeclarationOnSerialize, bo return writer.ToString(); } }, - xml => + graphml => { - using (var reader = new StringReader(xml)) + using (var reader = new StringReader(graphml)) { var serializer = new GraphMLDeserializer { @@ -616,9 +618,9 @@ private static string SerializeGraph4([NotNull] TestGraph graph) [Pure] [NotNull] - private static TestGraph DeserializeGraph([NotNull] string xml) + private static TestGraph DeserializeGraph([NotNull] string graphml) { - using (var reader = new StringReader(xml)) + using (var reader = new StringReader(graphml)) { var serializedGraph = new TestGraph(); serializedGraph.DeserializeAndValidateFromGraphML( @@ -842,5 +844,194 @@ public void DeserializeAndValidateFromGraphML_Throws() #endif #endregion + + #region Serialization/Deserialization + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize( + [NotNull] TInGraph graph, + [NotNull, InstantHandle] Func deserialize) + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph + { + Assert.IsNotNull(graph); + + using (var stream = new MemoryStream()) + { + // Serialize + using (XmlWriter writer = XmlWriter.Create(stream)) + { + graph.SerializeToGraphML( + writer, + vertex => vertex.ToString(), + graph.GetEdgeIdentity()); + } + + // Deserialize + stream.Position = 0; + + // Deserialize + using (XmlReader reader = XmlReader.Create(stream)) + { + TOutGraph deserializedGraph = deserialize(reader); + Assert.IsNotNull(deserializedGraph); + Assert.AreNotSame(graph, deserializedGraph); + return deserializedGraph; + } + } + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + return SerializeDeserialize, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + { + var deserializedGraph = new TOutGraph(); + deserializedGraph.DeserializeFromGraphML( + reader, + int.Parse, + (source, target, _) => new EquatableEdge(source, target)); + return deserializedGraph; + }); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_SEdge([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + return SerializeDeserialize, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => + { + var deserializedGraph = new TOutGraph(); + deserializedGraph.DeserializeFromGraphML( + reader, + int.Parse, + (source, target, _) => new SEquatableEdge(source, target)); + return deserializedGraph; + }); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Reversed([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph>> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + return SerializeDeserialize>, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + { + var deserializedGraph = new TOutGraph(); + deserializedGraph.DeserializeFromGraphML( + reader, + int.Parse, + (source, target, _) => new EquatableEdge(source, target)); + return deserializedGraph; + }); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] + public void GraphMLSerialization_AdjacencyGraph([NotNull] AdjacencyGraph> graph) + { + AdjacencyGraph> deserializedGraph1 = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayAdjacencyGraph>(graph); + AdjacencyGraph> deserializedGraph2 = + SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] + public void GraphMLSerialization_AdapterGraph([NotNull] AdjacencyGraph> graph) + { + var bidirectionalAdapterGraph = new BidirectionalAdapterGraph>(graph); + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(bidirectionalAdapterGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphTestCases))] + public void GraphMLSerialization_ClusteredGraph([NotNull] ClusteredAdjacencyGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphTestCases))] + public void GraphMLSerialization_CompressedGraph([NotNull] CompressedSparseRowGraph graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize_SEdge, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphTestCases))] + public void GraphMLSerialization_BidirectionalGraph([NotNull] BidirectionalGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + + var arrayGraph = new ArrayBidirectionalGraph>(graph); + AdjacencyGraph> deserializedGraph2 = + SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + + var reversedGraph = new ReversedBidirectionalGraph>(graph); + BidirectionalGraph> deserializedGraph3 = + SerializeDeserialize_Reversed>, BidirectionalGraph>>(reversedGraph); + Assert.IsTrue( + EquateGraphs.Equate( + graph, + deserializedGraph3, + EqualityComparer.Default, + LambdaEqualityComparer>.Create( + (edge1, edge2) => Equals(edge1.Source, edge2.Target) && Equals(edge1.Target, edge2.Source), + edge => edge.GetHashCode()))); + + var undirectedBidirectionalGraph = new UndirectedBidirectionalGraph>(graph); + UndirectedGraph> deserializedGraph4 = + SerializeDeserialize>, UndirectedGraph>>(undirectedBidirectionalGraph); + Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalMatrixGraphTestCases))] + public void GraphMLSerialization_BidirectionalMatrixGraph([NotNull] BidirectionalMatrixGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphTestCases))] + public void GraphMLSerialization_UndirectedGraph([NotNull] UndirectedGraph> graph) + { + UndirectedGraph> deserializedGraph1 = + SerializeDeserialize>, UndirectedGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayUndirectedGraph>(graph); + UndirectedGraph> deserializedGraph2 = + SerializeDeserialize>, UndirectedGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphTestCases))] + public void GraphMLSerialization_EdgeListGraph([NotNull] EdgeListGraph> graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + #endregion } } \ No newline at end of file From 36702b7254238eacd45cd91a078ffc483e23bb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 31 Oct 2021 13:27:00 +0100 Subject: [PATCH 15/39] Add missing define for QuikGraph.Graphviz. Add .NET 4.5 target as a consequence. --- src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj b/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj index 80339f406..9376eeb63 100644 --- a/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj +++ b/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj @@ -1,7 +1,7 @@ - net35;net40;netstandard1.3;netstandard2.0 + net35;net40;net45;netstandard1.3;netstandard2.0 $(Generate_QuikGraph_Graphviz) @@ -49,13 +49,17 @@ New: QuikGraph.Graphviz .NET 4.0 $(DefineConstants);NET40;SUPPORTS_SERIALIZATION;SUPPORTS_DESCRIPTION;SUPPORTS_SVG_CONVERSION;SUPPORTS_STREAM_FULL_FEATURES;SUPPORTS_BASIC_EXTENSIONS;$(AdditionalConstants) + + QuikGraph.Graphviz .NET 4.5 + $(DefineConstants);NET45;SUPPORTS_SERIALIZATION;SUPPORTS_DESCRIPTION;SUPPORTS_AGGRESSIVE_INLINING;SUPPORTS_SVG_CONVERSION;SUPPORTS_STREAM_FULL_FEATURES;SUPPORTS_BASIC_EXTENSIONS;$(AdditionalConstants) + QuikGraph.Graphviz .NET Standard 1.3 - $(DefineConstants);NETSTANDARD1_3;$(AdditionalConstants) + $(DefineConstants);NETSTANDARD1_3;SUPPORTS_AGGRESSIVE_INLINING;$(AdditionalConstants) QuikGraph.Graphviz .NET Standard 2.0 - $(DefineConstants);NETSTANDARD2_0;SUPPORTS_SERIALIZATION;SUPPORTS_DESCRIPTION;SUPPORTS_SVG_CONVERSION;SUPPORTS_STREAM_FULL_FEATURES;$(AdditionalConstants) + $(DefineConstants);NETSTANDARD2_0;SUPPORTS_SERIALIZATION;SUPPORTS_DESCRIPTION;SUPPORTS_AGGRESSIVE_INLINING;SUPPORTS_SVG_CONVERSION;SUPPORTS_STREAM_FULL_FEATURES;$(AdditionalConstants) From 53620e91b390989c6e691e42b26be64e431ed65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 1 Nov 2021 19:08:03 +0100 Subject: [PATCH 16/39] Improve the implementation of the Graphviz algorithm to better work with delegate graph implementations. Fix #41 --- src/QuikGraph.Graphviz/GraphvizAlgorithm.cs | 117 +++++++++++------- .../Extensions/GraphvizExtensionsTests.cs | 91 ++++++++++++++ 2 files changed, 164 insertions(+), 44 deletions(-) diff --git a/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs b/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs index 84dd59b5a..16f691d5e 100644 --- a/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs +++ b/src/QuikGraph.Graphviz/GraphvizAlgorithm.cs @@ -2,6 +2,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; using QuikGraph.Graphviz.Dot; @@ -175,11 +179,14 @@ public string Generate() Output = new StringWriter(); // Build vertex id map int i = 0; + var vertices = new HashSet(VisitedGraph.Vertices); foreach (TVertex vertex in VisitedGraph.Vertices) { _verticesIds.Add(vertex, i++); } + var edges = new HashSet(VisitedGraph.Edges); + Output.Write(VisitedGraph.IsDirected ? "digraph " : "graph "); Output.Write(GraphFormat.Name); Output.WriteLine(" {"); @@ -200,26 +207,13 @@ public string Generate() Output.WriteLine($"edge [{edgeFormat}];"); } - // Initialize vertices map - var verticesColors = new Dictionary(); - foreach (TVertex vertex in VisitedGraph.Vertices) - { - verticesColors[vertex] = GraphColor.White; - } - - var edgeColors = new Dictionary(); - foreach (TEdge edge in VisitedGraph.Edges) - { - edgeColors[edge] = GraphColor.White; - } - if (VisitedGraph is IClusteredGraph clusteredGraph) { - WriteClusters(verticesColors, edgeColors, clusteredGraph); + WriteClusters(vertices, edges, clusteredGraph); } - WriteVertices(verticesColors, VisitedGraph.Vertices); - WriteEdges(edgeColors, VisitedGraph.Edges); + WriteVertices(vertices); + WriteEdges(edges); Output.Write("}"); return Output.ToString(); @@ -244,12 +238,12 @@ public string Generate([NotNull] IDotEngine dot, [NotNull] string outputFilePath } private void WriteClusters( - [NotNull] IDictionary verticesColors, - [NotNull] IDictionary edgeColors, + [NotNull, ItemNotNull] ICollection remainingVertices, + [NotNull, ItemNotNull] ICollection remainingEdges, [NotNull] IClusteredGraph parent) { - Debug.Assert(verticesColors != null); - Debug.Assert(edgeColors != null); + Debug.Assert(remainingVertices != null); + Debug.Assert(remainingEdges != null); Debug.Assert(parent != null); ++ClusterCount; @@ -260,65 +254,100 @@ private void WriteClusters( OnFormatCluster(subGraph); if (subGraph is IClusteredGraph clusteredGraph) { - WriteClusters(verticesColors, edgeColors, clusteredGraph); + WriteClusters(remainingVertices, remainingEdges, clusteredGraph); } if (parent.Collapsed) { foreach (TVertex vertex in subGraph.Vertices) { - verticesColors[vertex] = GraphColor.Black; + remainingVertices.Remove(vertex); } foreach (TEdge edge in subGraph.Edges) { - edgeColors[edge] = GraphColor.Black; + remainingEdges.Remove(edge); } } else { - WriteVertices(verticesColors, subGraph.Vertices); - WriteEdges(edgeColors, subGraph.Edges); + WriteVertices(remainingVertices, subGraph.Vertices); + WriteEdges(remainingEdges, subGraph.Edges); } Output.WriteLine("}"); } } - private void WriteVertices( - [NotNull] IDictionary verticesColors, - [NotNull, ItemNotNull] IEnumerable vertices) +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void WriteVertex([NotNull] TVertex vertex) + { + Debug.Assert(vertex != null); + + OnFormatVertex(vertex); + } + + private void WriteVertices([NotNull, ItemNotNull] IEnumerable vertices) { - Debug.Assert(verticesColors != null); Debug.Assert(vertices != null); foreach (TVertex vertex in vertices) { - if (verticesColors[vertex] != GraphColor.White) - continue; + WriteVertex(vertex); + } + } - OnFormatVertex(vertex); - verticesColors[vertex] = GraphColor.Black; + private void WriteVertices( + [NotNull, ItemNotNull] ICollection remainingVertices, + [NotNull, ItemNotNull] IEnumerable vertices) + { + Debug.Assert(remainingVertices != null); + Debug.Assert(vertices != null); + + foreach (TVertex vertex in vertices.Where(remainingVertices.Contains)) + { + WriteVertex(vertex); + remainingVertices.Remove(vertex); } } - private void WriteEdges( - [NotNull] IDictionary edgesColors, - [NotNull, ItemNotNull] IEnumerable edges) +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void WriteEdge([NotNull] TEdge edge) + { + Debug.Assert(edge != null); + + Output.Write(VisitedGraph.IsDirected + ? $"{_verticesIds[edge.Source]} -> {_verticesIds[edge.Target]}" + : $"{_verticesIds[edge.Source]} -- {_verticesIds[edge.Target]}"); + + OnFormatEdge(edge); + } + + private void WriteEdges([NotNull, ItemNotNull] IEnumerable edges) { - Debug.Assert(edgesColors != null); Debug.Assert(edges != null); foreach (TEdge edge in edges) { - if (edgesColors[edge] != GraphColor.White) - continue; + WriteEdge(edge); + } + } - Output.Write(VisitedGraph.IsDirected - ? $"{_verticesIds[edge.Source]} -> {_verticesIds[edge.Target]}" - : $"{_verticesIds[edge.Source]} -- {_verticesIds[edge.Target]}"); - OnFormatEdge(edge); - edgesColors[edge] = GraphColor.Black; + private void WriteEdges( + [NotNull, ItemNotNull] ICollection remainingEdges, + [NotNull, ItemNotNull] IEnumerable edges) + { + Debug.Assert(remainingEdges != null); + Debug.Assert(edges != null); + + foreach (TEdge edge in edges.Where(remainingEdges.Contains)) + { + WriteEdge(edge); + remainingEdges.Remove(edge); } } } diff --git a/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs b/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs index 67d0da1c9..4541acdf7 100644 --- a/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs +++ b/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Text; @@ -41,6 +42,96 @@ public void ToGraphviz() Assert.AreEqual(expectedDot, dotGraph); } + [Test] + public void ToGraphviz_DelegateGraph() + { + int[] vertices = { 1, 2, 3, 4, 5 }; + var graph = new DelegateVertexAndEdgeListGraph>( + vertices, + (int vertex, out IEnumerable> outEdges) => + { + if (vertex == 1) + { + outEdges = new[] { new Edge(1, 2), new Edge(1, 3) }; + return true; + } + + if (vertex == 2) + { + outEdges = new[] { new Edge(2, 4) }; + return true; + } + + if (vertex is 3 or 4 or 5) + { + outEdges = new Edge[] { }; + return true; + } + + outEdges = null; + return false; + }); + + string expectedDot = + @"digraph G {" + Environment.NewLine + + @"0;" + Environment.NewLine + + @"1;" + Environment.NewLine + + @"2;" + Environment.NewLine + + @"3;" + Environment.NewLine + + @"4;" + Environment.NewLine + + @"0 -> 1;" + Environment.NewLine + + @"0 -> 2;" + Environment.NewLine + + @"1 -> 3;" + Environment.NewLine + + @"}"; + string dotGraph = graph.ToGraphviz(); + Assert.AreEqual(expectedDot, dotGraph); + } + + [Test] + public void ToGraphviz_EquatableEdgeDelegateGraph() + { + int[] vertices = { 1, 2, 3, 4, 5 }; + var graph = new DelegateVertexAndEdgeListGraph>( + vertices, + (int vertex, out IEnumerable> outEdges) => + { + if (vertex == 1) + { + outEdges = new[] { new EquatableEdge(1, 2), new EquatableEdge(1, 3) }; + return true; + } + + if (vertex == 2) + { + outEdges = new[] { new EquatableEdge(2, 4) }; + return true; + } + + if (vertex is 3 or 4 or 5) + { + outEdges = new EquatableEdge[] { }; + return true; + } + + outEdges = null; + return false; + }); + + string expectedDot = + @"digraph G {" + Environment.NewLine + + @"0;" + Environment.NewLine + + @"1;" + Environment.NewLine + + @"2;" + Environment.NewLine + + @"3;" + Environment.NewLine + + @"4;" + Environment.NewLine + + @"0 -> 1;" + Environment.NewLine + + @"0 -> 2;" + Environment.NewLine + + @"1 -> 3;" + Environment.NewLine + + @"}"; + string dotGraph = graph.ToGraphviz(); + Assert.AreEqual(expectedDot, dotGraph); + } + [Test] public void ToGraphvizWithEmptyInit() { From b733c1cdb0f24368af7200adac799ee1dd800744 Mon Sep 17 00:00:00 2001 From: Maxime Laudrin Date: Wed, 9 Feb 2022 11:48:46 +0100 Subject: [PATCH 17/39] Fix input type of transitive reduction/closure algorithms. --- src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs | 4 ++-- src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs | 4 ++-- src/QuikGraph/Extensions/AlgorithmExtensions.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs b/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs index 79de5e3bf..7dbed14c7 100644 --- a/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TransitiveClosureAlgorithm.cs @@ -9,7 +9,7 @@ namespace QuikGraph.Algorithms /// /// Vertex type. /// Edge type. - public class TransitiveClosureAlgorithm : AlgorithmBase> + public class TransitiveClosureAlgorithm : AlgorithmBase> where TEdge : IEdge { ///

@@ -20,7 +20,7 @@ public class TransitiveClosureAlgorithm : AlgorithmBase is . /// is . public TransitiveClosureAlgorithm( - [NotNull] BidirectionalGraph visitedGraph, + [NotNull] IEdgeListGraph visitedGraph, [NotNull] Func edgeFactory) : base(visitedGraph) { diff --git a/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs b/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs index 5cb043be8..3d6da9e58 100644 --- a/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs +++ b/src/QuikGraph/Algorithms/TransitiveReductionAlgorithm.cs @@ -8,7 +8,7 @@ namespace QuikGraph.Algorithms /// /// Vertex type. /// Edge type. - public class TransitiveReductionAlgorithm : AlgorithmBase> + public class TransitiveReductionAlgorithm : AlgorithmBase> where TEdge : IEdge { /// @@ -17,7 +17,7 @@ public class TransitiveReductionAlgorithm : AlgorithmBaseGraph to visit. /// is . public TransitiveReductionAlgorithm( - [NotNull] BidirectionalGraph visitedGraph) + [NotNull] IEdgeListGraph visitedGraph) : base(visitedGraph) { TransitiveReduction = new BidirectionalGraph(); diff --git a/src/QuikGraph/Extensions/AlgorithmExtensions.cs b/src/QuikGraph/Extensions/AlgorithmExtensions.cs index 33169f02d..b0d85a714 100644 --- a/src/QuikGraph/Extensions/AlgorithmExtensions.cs +++ b/src/QuikGraph/Extensions/AlgorithmExtensions.cs @@ -1191,7 +1191,7 @@ public static double MaximumFlow( [Pure] [NotNull] public static BidirectionalGraph ComputeTransitiveReduction( - [NotNull] this BidirectionalGraph graph) + [NotNull] this IEdgeListGraph graph) where TEdge : IEdge { var algorithm = new TransitiveReductionAlgorithm(graph); @@ -1212,7 +1212,7 @@ public static BidirectionalGraph ComputeTransitiveReduction ComputeTransitiveClosure( - [NotNull] this BidirectionalGraph graph, + [NotNull] this IEdgeListGraph graph, [NotNull] Func edgeFactory) where TEdge : IEdge { From e1bb3b4167b742610928ba737a35a8f4dc8fc104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 13 Feb 2022 19:51:36 +0100 Subject: [PATCH 18/39] Also relax type of graph used in tests (will allow to make sure we keep a wide API compliance). --- .../TransitiveClosureAlgorithmTests.cs | 16 ++++++++-------- .../TransitiveReductionAlgorithmTests.cs | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/QuikGraph.Tests/Algorithms/TransitiveClosureAlgorithmTests.cs b/tests/QuikGraph.Tests/Algorithms/TransitiveClosureAlgorithmTests.cs index f28d82e36..433b49485 100644 --- a/tests/QuikGraph.Tests/Algorithms/TransitiveClosureAlgorithmTests.cs +++ b/tests/QuikGraph.Tests/Algorithms/TransitiveClosureAlgorithmTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; using QuikGraph.Algorithms; using static QuikGraph.Tests.Algorithms.AlgorithmTestHelpers; @@ -15,7 +15,7 @@ internal sealed class TransitiveClosureAlgorithmTests [Test] public void Constructor() { - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); var algorithm = new TransitiveClosureAlgorithm>(graph, (v1, v2) => new Edge(v1, v2)); AssertAlgorithmState(algorithm, graph); Assert.IsNotNull(algorithm.TransitiveClosure); @@ -24,7 +24,7 @@ public void Constructor() [Test] public void Constructor_Throws() { - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); // ReSharper disable ObjectCreationAsStatement // ReSharper disable AssignNullToNotNullAttribute Assert.Throws( @@ -41,7 +41,7 @@ public void Constructor_Throws() public void TransitiveClosure_ValueType() { // Test 1 - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { new SEquatableEdge(1, 2), @@ -60,7 +60,7 @@ public void TransitiveClosure_ValueType() }); // Test 2 - graph = new BidirectionalGraph>(); + graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { new SEquatableEdge(1, 2), @@ -91,7 +91,7 @@ public void TransitiveClosure_ValueType() public void TransitiveClosure_ReferenceType() { // Test 1 - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { new EquatableEdge(1, 2), @@ -110,7 +110,7 @@ public void TransitiveClosure_ReferenceType() }); // Test 2 - graph = new BidirectionalGraph>(); + graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { new EquatableEdge(1, 2), @@ -147,7 +147,7 @@ public void TransitiveClosure_IsolatedVertices() var edge12 = new EquatableEdge(vertex1, vertex2); var edge23 = new EquatableEdge(vertex2, vertex3); - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); graph.AddVertexRange(new[] { vertex1, vertex2, vertex3, vertex4 }); graph.AddEdgeRange(new[] { edge12, edge23 }); diff --git a/tests/QuikGraph.Tests/Algorithms/TransitiveReductionAlgorithmTests.cs b/tests/QuikGraph.Tests/Algorithms/TransitiveReductionAlgorithmTests.cs index 1ff295022..93b58ada2 100644 --- a/tests/QuikGraph.Tests/Algorithms/TransitiveReductionAlgorithmTests.cs +++ b/tests/QuikGraph.Tests/Algorithms/TransitiveReductionAlgorithmTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; using QuikGraph.Algorithms; using static QuikGraph.Tests.Algorithms.AlgorithmTestHelpers; @@ -15,7 +15,7 @@ internal sealed class TransitiveReductionAlgorithmTests [Test] public void Constructor() { - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); var algorithm = new TransitiveReductionAlgorithm>(graph); AssertAlgorithmState(algorithm, graph); Assert.IsNotNull(algorithm.TransitiveReduction); @@ -42,7 +42,7 @@ public void TransitiveReduction_ValueType() var edge34 = new SEdge(3, 4); var edge35 = new SEdge(3, 5); var edge45 = new SEdge(4, 5); - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { edge12, edge13, edge14, edge15, @@ -65,7 +65,7 @@ public void TransitiveReduction_ValueType() var edge65 = new SEdge(6, 5); var edge67 = new SEdge(6, 7); var edge74 = new SEdge(7, 4); - graph = new BidirectionalGraph>(); + graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { edge01, edge02, edge03, edge23, @@ -92,7 +92,7 @@ public void TransitiveReduction_ReferenceType() var edge34 = new Edge(3, 4); var edge35 = new Edge(3, 5); var edge45 = new Edge(4, 5); - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { edge12, edge13, edge14, edge15, @@ -114,7 +114,7 @@ public void TransitiveReduction_ReferenceType() var edge65 = new Edge(6, 5); var edge67 = new Edge(6, 7); var edge74 = new Edge(7, 4); - graph = new BidirectionalGraph>(); + graph = new AdjacencyGraph>(); graph.AddVerticesAndEdgeRange(new[] { edge01, edge02, edge03, edge23, @@ -137,7 +137,7 @@ public void TransitiveReduction_IsolatedVertices() const string vertex3 = "/test/notlinked"; var edge12 = new Edge(vertex1, vertex2); - var graph = new BidirectionalGraph>(); + var graph = new AdjacencyGraph>(); graph.AddVertexRange(new[] { vertex1, vertex2, vertex3 }); graph.AddEdge(edge12); From 0bac9027635cc3f7ec2b6bffbeab0b3c1b9477da Mon Sep 17 00:00:00 2001 From: Yannick Date: Mon, 14 Feb 2022 06:44:40 +0800 Subject: [PATCH 19/39] Make QuikGraph projects CLS compliant (#52) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make QuikGraph projects CLS compliant so that its interfaces can be exposed in CLS compliant projects. Fix #52 Co-authored-by: Yannick Morin-Rivest Co-authored-by: Alexandre Rabérin --- src/QuikGraph.Data/Properties/AssemblyInfo.cs | 3 + .../Properties/AssemblyInfo.cs | 3 + .../Properties/AssemblyInfo.cs | 2 + .../DirectedGraphML/Dgml.cs | 181 ++++++++++-------- .../DirectedGraphMLAlgorithm.cs | 1 + .../DirectedGraphMLExtensions.cs | 1 + .../Properties/AssemblyInfo.cs | 2 + src/QuikGraph/Properties/AssemblyInfo.cs | 2 + 8 files changed, 113 insertions(+), 82 deletions(-) create mode 100644 src/QuikGraph.Data/Properties/AssemblyInfo.cs create mode 100644 src/QuikGraph.Graphviz/Properties/AssemblyInfo.cs diff --git a/src/QuikGraph.Data/Properties/AssemblyInfo.cs b/src/QuikGraph.Data/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a46fb3bed --- /dev/null +++ b/src/QuikGraph.Data/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System; + +[assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/src/QuikGraph.Graphviz/Properties/AssemblyInfo.cs b/src/QuikGraph.Graphviz/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a46fb3bed --- /dev/null +++ b/src/QuikGraph.Graphviz/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System; + +[assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/src/QuikGraph.Petri/Properties/AssemblyInfo.cs b/src/QuikGraph.Petri/Properties/AssemblyInfo.cs index 4e3f9f725..c06a51187 100644 --- a/src/QuikGraph.Petri/Properties/AssemblyInfo.cs +++ b/src/QuikGraph.Petri/Properties/AssemblyInfo.cs @@ -1,4 +1,6 @@ +using System; using System.Runtime.CompilerServices; using QuikGraph; +[assembly: CLSCompliant(true)] [assembly: InternalsVisibleTo("QuikGraph.Petri.Tests" + PublicKey.Key)] \ No newline at end of file diff --git a/src/QuikGraph.Serialization/DirectedGraphML/Dgml.cs b/src/QuikGraph.Serialization/DirectedGraphML/Dgml.cs index b6bb1420e..d0fb99372 100644 --- a/src/QuikGraph.Serialization/DirectedGraphML/Dgml.cs +++ b/src/QuikGraph.Serialization/DirectedGraphML/Dgml.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.21006.1 @@ -11,21 +11,25 @@ // // This source code was auto-generated by xsd, Version=4.0.21006.1. // + +using System; +using System.CodeDom.Compiler; +using System.ComponentModel; +using System.Diagnostics; +using System.Xml.Serialization; + namespace QuikGraph.Serialization.DirectedGraphML { -#if SUPPORTS_SERIALIZATION - using System; -#endif - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] - [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml", IsNullable = false)] + [DebuggerStepThrough] + [DesignerCategory("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlRoot(Namespace = "http://schemas.microsoft.com/vs/2009/dgml", IsNullable = false)] public partial class DirectedGraph { @@ -335,13 +339,14 @@ public string ZoomLevel } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphNode { @@ -2635,13 +2640,14 @@ public string CodeSchemaProperty_StatementType } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphNodeCategory { @@ -2663,11 +2669,11 @@ public string Ref } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum HorizontalAlignmentEnum { @@ -2682,11 +2688,11 @@ public enum HorizontalAlignmentEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum VerticalAlignmentEnum { @@ -2701,11 +2707,11 @@ public enum VerticalAlignmentEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum GroupEnum { @@ -2717,11 +2723,12 @@ public enum GroupEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum ClrBoolean { @@ -2739,11 +2746,11 @@ public enum ClrBoolean } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum VisibilityEnum { @@ -2758,11 +2765,11 @@ public enum VisibilityEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum FontStyleEnum { @@ -2777,11 +2784,11 @@ public enum FontStyleEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum FontWeightEnum { @@ -2835,11 +2842,11 @@ public enum FontWeightEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum FrameKindEnum { @@ -2857,13 +2864,14 @@ public enum FrameKindEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphLink { @@ -3205,13 +3213,14 @@ public bool AttractConsumersSpecified } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphLinkCategory { @@ -3233,13 +3242,14 @@ public string Ref } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphCategory { @@ -3869,13 +3879,14 @@ public string OutboundName } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphProperty { @@ -4009,13 +4020,14 @@ public string ReferenceTemplate } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphName { @@ -4085,13 +4097,14 @@ public string Formatter } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphAlias { @@ -4145,13 +4158,14 @@ public string Id } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphStyle { @@ -4284,13 +4298,14 @@ public string ToolTip } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphStyleCondition { @@ -4312,13 +4327,14 @@ public string Expression } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphStyleSetter { @@ -4372,11 +4388,11 @@ public string Expression } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum PropertyType { @@ -4436,11 +4452,11 @@ public enum PropertyType } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum TargetTypeEnum { @@ -4452,13 +4468,14 @@ public enum TargetTypeEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [CLSCompliant(false)] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [DebuggerStepThrough] + [DesignerCategoryAttribute("code")] + [XmlType(AnonymousType = true, Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public partial class DirectedGraphPath { @@ -4496,11 +4513,11 @@ public string Value } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum GraphDirectionEnum { @@ -4518,11 +4535,11 @@ public enum GraphDirectionEnum } /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.21006.1")] + [GeneratedCode("xsd", "4.0.21006.1")] #if SUPPORTS_SERIALIZATION [Serializable] #endif - [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] + [XmlType(Namespace = "http://schemas.microsoft.com/vs/2009/dgml")] public enum LayoutEnum { diff --git a/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs b/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs index a32fa5237..6d564ea3a 100644 --- a/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs +++ b/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs @@ -13,6 +13,7 @@ namespace QuikGraph.Serialization /// /// Vertex type. /// Edge type. + [CLSCompliant(false)] public sealed class DirectedGraphMLAlgorithm : AlgorithmBase> where TEdge : IEdge { diff --git a/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs b/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs index 3b586c5fd..10a0403af 100644 --- a/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs +++ b/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs @@ -12,6 +12,7 @@ namespace QuikGraph.Serialization /// /// Directed graph Markup Language extensions. /// + [CLSCompliant(false)] public static class DirectedGraphMLExtensions { [CanBeNull] diff --git a/src/QuikGraph.Serialization/Properties/AssemblyInfo.cs b/src/QuikGraph.Serialization/Properties/AssemblyInfo.cs index a8cfb2858..add46e056 100644 --- a/src/QuikGraph.Serialization/Properties/AssemblyInfo.cs +++ b/src/QuikGraph.Serialization/Properties/AssemblyInfo.cs @@ -1,4 +1,6 @@ +using System; using System.Runtime.CompilerServices; using QuikGraph; +[assembly: CLSCompliant(true)] [assembly: InternalsVisibleTo("QuikGraph.Serialization.Tests" + PublicKey.Key)] \ No newline at end of file diff --git a/src/QuikGraph/Properties/AssemblyInfo.cs b/src/QuikGraph/Properties/AssemblyInfo.cs index 977af4c3d..68271599f 100644 --- a/src/QuikGraph/Properties/AssemblyInfo.cs +++ b/src/QuikGraph/Properties/AssemblyInfo.cs @@ -1,4 +1,6 @@ +using System; using System.Runtime.CompilerServices; using QuikGraph; +[assembly: CLSCompliant(true)] [assembly: InternalsVisibleTo("QuikGraph.Tests" + PublicKey.Key)] \ No newline at end of file From 44a88b95de15c265e59e25f611992bf19d9a5a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 13 Feb 2022 23:47:45 +0100 Subject: [PATCH 20/39] Add contributors to readme. --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eec9f4b30..2db4c51e0 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,10 @@ QuikGraph is available on [NuGet](https://www.nuget.org) in several modules. This project exists thanks to all the people who have contributed to the code base. -[![](https://github.com/jnyrup.png?size=50)](https://github.com/jnyrup) -[![](https://github.com/SimonTC.png?size=50)](https://github.com/SimonTC) -[![](https://github.com/tuwuhs.png?size=50)](https://github.com/tuwuhs) +[](https://github.com/jnyrup) +[](https://github.com/SimonTC) +[](https://github.com/tuwuhs) +[](https://github.com/gropax) +[](https://github.com/Yannike) --- \ No newline at end of file From 2f9dc5ef6dbfa5b141c3e68bd68b906b13491dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Thu, 24 Mar 2022 00:39:17 +0100 Subject: [PATCH 21/39] Fix typos and minor doc adjustements. --- docs/documentation/history.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/documentation/history.md b/docs/documentation/history.md index 5fed75fec..ab6922a74 100644 --- a/docs/documentation/history.md +++ b/docs/documentation/history.md @@ -1,16 +1,22 @@ # Library history +## Overview + Below is some summarized information about the history of this library in order to have a better idea of where it comes from. +- [QuickGraph](#QuickGraph) +- [YC.QuickGraph](#YC.QuickGraph) +- [QuikGraph](#QuikGraph) <= Here we are + ## QuickGraph ### General information This is the original library supporting .NET Framework 4.0, Silverlight 4.0, Windows Phone 7, Windows 8 Metro Apps, XBox 360. -QuikGraph was originally created by Jonathan "Peli" de Halleux in 2003. +QuickGraph was originally created by Jonathan "Peli" de Halleux in 2003. -Intially the library was providing generic directed/undirected graph datastructures and algorithms for .NET. +Initially the library was providing generic directed/undirected graph data structures and algorithms for .NET. QuickGraph was coming with algorithms such as depth first seach, breath first search, A* search, shortest path, k-shortest path, maximum flow, minimum spanning tree, least common ancestors, etc... QuickGraph was supporting [MSAGL](https://www.microsoft.com/en-us/research/project/microsoft-automatic-graph-layout), [GLEE](https://en.wikipedia.org/wiki/Microsoft_Automatic_Graph_Layout), and [Graphviz](https://www.graphviz.org) to render the graphs, serialization to [GraphML](http://graphml.graphdrawing.org), etc... From a8dd78bfc09cfc2e69dc2cf4b8ae4436dfbc69b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Thu, 24 Mar 2022 00:44:39 +0100 Subject: [PATCH 22/39] Minor projects update. --- .gitignore | 22 ------------------- ...ialization.Tests.CommonInternals.projitems | 2 +- .../QuikGraph.Tests.CommonInternals.projitems | 10 +-------- 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index da77057f0..94c45d53c 100644 --- a/.gitignore +++ b/.gitignore @@ -217,23 +217,6 @@ $RECYCLE.BIN/ # Mac desktop service store files .DS_Store -DotParserProject/DotParserProject/DotGrammar.yrd.orig -DotParserProject/DotParserProject/DotParser.fs.orig -DotParserProject/DotParserProject/Program.fs.orig -DotParserProject/packages/QuickGraph.3.6.61119.7/QuickGraph.3.6.61119.7.nupkg -DotParserProject/packages/QuickGraph.3.6.61119.7/QuickGraph.3.6.61119.7.nuspec -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/CodeContracts/QuickGraph.Contracts.dll -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/CodeContracts/QuickGraph.Data.Contracts.dll -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/CodeContracts/QuickGraph.Graphviz.Contracts.dll -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/CodeContracts/QuickGraph.Serialization.Contracts.dll -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.Data.XML -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.Data.dll -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.Graphviz.XML -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.Graphviz.dll -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.Serialization.XML -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.Serialization.dll -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.XML -DotParserProject/packages/QuickGraph.3.6.61119.7/lib/net4/QuickGraph.dll # =================================================== @@ -265,14 +248,9 @@ docs/content/release-notes.md .fake TestResults/ *.bak -QuickGraph.5.1.TeamCity.user -QuickGraph.sln.docstates User_*/Out/* *.trx - -tests/QuickGraph.FST.Tests/DOTfst/* -tests/QuickGraph.FSA.Tests/DOTfsa/* *.orig .paket/ diff --git a/tests/QuikGraph.Serialization.Tests.CommonInternals/QuikGraph.Serialization.Tests.CommonInternals.projitems b/tests/QuikGraph.Serialization.Tests.CommonInternals/QuikGraph.Serialization.Tests.CommonInternals.projitems index 50f47e9f4..28afcc052 100644 --- a/tests/QuikGraph.Serialization.Tests.CommonInternals/QuikGraph.Serialization.Tests.CommonInternals.projitems +++ b/tests/QuikGraph.Serialization.Tests.CommonInternals/QuikGraph.Serialization.Tests.CommonInternals.projitems @@ -9,6 +9,6 @@ QuikGraph.Serialization.Tests.CommonInternals - + \ No newline at end of file diff --git a/tests/QuikGraph.Tests.CommonInternals/QuikGraph.Tests.CommonInternals.projitems b/tests/QuikGraph.Tests.CommonInternals/QuikGraph.Tests.CommonInternals.projitems index d3ede33b9..68674b348 100644 --- a/tests/QuikGraph.Tests.CommonInternals/QuikGraph.Tests.CommonInternals.projitems +++ b/tests/QuikGraph.Tests.CommonInternals/QuikGraph.Tests.CommonInternals.projitems @@ -9,14 +9,6 @@ QuikGraph.Tests.CommonInternals - - - - - - - - - + \ No newline at end of file From 0dadad97beb79799c7b64e5a1b6afa55c576886a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Thu, 24 Mar 2022 00:45:20 +0100 Subject: [PATCH 23/39] Soft deprecate ToSvg API no more working. Target web service is down. --- .../Extensions/GraphvizExtensions.cs | 3 +++ .../Extensions/GraphvizExtensionsTests.cs | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs b/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs index a4c83a27c..8380ab8de 100644 --- a/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs +++ b/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs @@ -73,6 +73,7 @@ public static string ToGraphviz( /// is . [Pure] [NotNull] + [Obsolete("Conversion is using an external web service that is no longer available.")] public static string ToSvg([NotNull] this IEdgeListGraph graph) where TEdge : IEdge { @@ -93,6 +94,7 @@ public static string ToSvg([NotNull] this IEdgeListGraph is . [Pure] [NotNull] + [Obsolete("Conversion is using an external web service that is no longer available.")] public static string ToSvg( [NotNull] this IEdgeListGraph graph, [NotNull, InstantHandle] Action> initAlgorithm) @@ -110,6 +112,7 @@ public static string ToSvg( /// is . [Pure] [NotNull] + [Obsolete("Conversion is using an external web service that is no longer available.")] public static string ToSvg([NotNull] string dot) { if (dot is null) diff --git a/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs b/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs index 4541acdf7..b7a0367d8 100644 --- a/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs +++ b/tests/QuikGraph.Graphviz.Tests/Extensions/GraphvizExtensionsTests.cs @@ -524,7 +524,9 @@ public void ToSvg() AdjacencyGraph> graph = CreateTestGraph(); +#pragma warning disable CS0618 Assert.AreEqual(expectedSvg, graph.ToSvg()); +#pragma warning restore CS0618 } [Test] @@ -537,7 +539,9 @@ public void ToSvg_Failure() AdjacencyGraph> graph = CreateTestGraph(); +#pragma warning disable CS0618 Assert.IsEmpty(graph.ToSvg()); +#pragma warning restore CS0618 } [Test] @@ -551,12 +555,14 @@ public void ToSvgWithInit() AdjacencyGraph> graph = CreateTestGraph(); +#pragma warning disable CS0618 Assert.AreEqual( expectedSvg, graph.ToSvg(algorithm => { algorithm.CommonVertexFormat.ToolTip = "Test vertex"; })); +#pragma warning restore CS0618 } [Test] @@ -564,9 +570,11 @@ public void ToSvgWithInit_Throws() { var graph = new AdjacencyGraph>(); +#pragma warning disable CS0618 // ReSharper disable once ReturnValueOfPureMethodIsNotUsed // ReSharper disable once AssignNullToNotNullAttribute Assert.Throws(() => graph.ToSvg(null)); +#pragma warning restore CS0618 } [Test] @@ -579,20 +587,24 @@ public void ToSvgWithInit_Failure() AdjacencyGraph> graph = CreateTestGraph(); +#pragma warning disable CS0618 Assert.IsEmpty( graph.ToSvg( algorithm => { algorithm.CommonVertexFormat.ToolTip = "Test vertex"; })); +#pragma warning restore CS0618 } [Test] public void DotToSvg_Throws() { +#pragma warning disable CS0618 // ReSharper disable once ReturnValueOfPureMethodIsNotUsed // ReSharper disable once AssignNullToNotNullAttribute Assert.Throws(() => GraphvizExtensions.ToSvg(null)); +#pragma warning restore CS0618 } } } \ No newline at end of file From 2b1187b6489d1512bc9ef0513eac27a2e09671f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Thu, 24 Mar 2022 00:46:04 +0100 Subject: [PATCH 24/39] Replace deprecated random API by new one. --- src/QuikGraph/Helpers/CryptoRandom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QuikGraph/Helpers/CryptoRandom.cs b/src/QuikGraph/Helpers/CryptoRandom.cs index 62274fa8e..5e7e6cdc6 100644 --- a/src/QuikGraph/Helpers/CryptoRandom.cs +++ b/src/QuikGraph/Helpers/CryptoRandom.cs @@ -15,7 +15,7 @@ namespace QuikGraph.Utils public class CryptoRandom : Random { [NotNull] - private readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); + private readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create(); [NotNull] private readonly byte[] _uint32Buffer = new byte[4]; From f69866abf12099e78eacf0507ea4f1c2d2320b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sat, 26 Mar 2022 17:32:01 +0100 Subject: [PATCH 25/39] Simplify and remove useless defines. --- .../CyclePoppingRandomTreeAlgorithm.cs | 9 +------ .../RandomWalks/MarkovEdgeChainBase.cs | 9 +------ ...inimumVertexCoverApproximationAlgorithm.cs | 15 ------------ src/QuikGraph/Helpers/CryptoRandom.cs | 6 ++--- src/QuikGraph/QuikGraph.csproj | 8 +++---- .../QuikGraph.Tests/Misc/CryptoRandomTests.cs | 6 ++--- tests/QuikGraph.Tests/QuikGraph.Tests.csproj | 24 +++++++++---------- 7 files changed, 22 insertions(+), 55 deletions(-) diff --git a/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs b/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs index d3b797578..991507511 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/CyclePoppingRandomTreeAlgorithm.cs @@ -4,9 +4,7 @@ using System.Linq; using JetBrains.Annotations; using QuikGraph.Algorithms.Services; -#if SUPPORTS_CRYPTO_RANDOM using QuikGraph.Utils; -#endif namespace QuikGraph.Algorithms.RandomWalks { @@ -87,12 +85,7 @@ public GraphColor GetVertexColor(TVertex vertex) public IMarkovEdgeChain EdgeChain { get; } [NotNull] - private Random _rand = -#if SUPPORTS_CRYPTO_RANDOM - new CryptoRandom((int)DateTime.Now.Ticks); -#else - new Random((int)DateTime.Now.Ticks); -#endif + private Random _rand = new CryptoRandom((int)DateTime.Now.Ticks); /// /// Gets or sets the random number generator used in . diff --git a/src/QuikGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs b/src/QuikGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs index 6b06ba224..05202b3e3 100644 --- a/src/QuikGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs +++ b/src/QuikGraph/Algorithms/RandomWalks/MarkovEdgeChainBase.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -#if SUPPORTS_CRYPTO_RANDOM using QuikGraph.Utils; -#endif namespace QuikGraph.Algorithms.RandomWalks { @@ -18,12 +16,7 @@ public abstract class MarkovEdgeChainBase : IMarkovEdgeChain { /// - public Random Rand { get; set; } = -#if SUPPORTS_CRYPTO_RANDOM - new CryptoRandom(); -#else - new Random(); -#endif + public Random Rand { get; set; } = new CryptoRandom(); /// public abstract bool TryGetSuccessor(IImplicitGraph graph, TVertex vertex, out TEdge successor); diff --git a/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs b/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs index 496ab5627..376ca0938 100644 --- a/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs +++ b/src/QuikGraph/Algorithms/VertexCover/MinimumVertexCoverApproximationAlgorithm.cs @@ -2,9 +2,7 @@ using System.Linq; using JetBrains.Annotations; using QuikGraph.Collections; -#if SUPPORTS_CRYPTO_RANDOM using QuikGraph.Utils; -#endif namespace QuikGraph.Algorithms.VertexCover { @@ -24,7 +22,6 @@ public sealed class MinimumVertexCoverApproximationAlgorithm : A [NotNull] private readonly Random _rng; -#if SUPPORTS_CRYPTO_RANDOM /// /// Initializes a new instance of the class. /// @@ -36,18 +33,6 @@ public MinimumVertexCoverApproximationAlgorithm( : this(graph, new CryptoRandom()) { } -#else - /// - /// Initializes a new instance of the class. - /// - /// Graph to compute the cover. - /// is . - public MinimumVertexCoverApproximationAlgorithm( - [NotNull] IUndirectedGraph graph) - : this(graph, new Random()) - { - } -#endif /// /// Initializes a new instance of the class. diff --git a/src/QuikGraph/Helpers/CryptoRandom.cs b/src/QuikGraph/Helpers/CryptoRandom.cs index 5e7e6cdc6..c4c46b5bc 100644 --- a/src/QuikGraph/Helpers/CryptoRandom.cs +++ b/src/QuikGraph/Helpers/CryptoRandom.cs @@ -1,5 +1,4 @@ -#if SUPPORTS_CRYPTO_RANDOM -using System; +using System; using System.Security.Cryptography; using JetBrains.Annotations; @@ -89,5 +88,4 @@ public override void NextBytes(byte[] buffer) _rng.GetBytes(buffer); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/QuikGraph/QuikGraph.csproj b/src/QuikGraph/QuikGraph.csproj index 028bab8b9..ba0952f08 100644 --- a/src/QuikGraph/QuikGraph.csproj +++ b/src/QuikGraph/QuikGraph.csproj @@ -57,16 +57,16 @@ Misc: QuikGraph .NET 3.5 - $(DefineConstants);NET35;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) + $(DefineConstants);NET35;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;$(AdditionalConstants) true QuikGraph .NET 4.0 - $(DefineConstants);NET40;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_SORTEDSET;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) + $(DefineConstants);NET40;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_SORTEDSET;$(AdditionalConstants) QuikGraph .NET 4.5 - $(DefineConstants);NET45;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_SORTEDSET;SUPPORTS_AGGRESSIVE_INLINING;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) + $(DefineConstants);NET45;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_SORTEDSET;SUPPORTS_AGGRESSIVE_INLINING;$(AdditionalConstants) QuikGraph .NET Standard 1.3 @@ -74,6 +74,6 @@ Misc: QuikGraph .NET Standard 2.0 - $(DefineConstants);NETSTANDARD2_0;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_SORTEDSET;SUPPORTS_AGGRESSIVE_INLINING;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) + $(DefineConstants);NETSTANDARD2_0;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_SORTEDSET;SUPPORTS_AGGRESSIVE_INLINING;$(AdditionalConstants) \ No newline at end of file diff --git a/tests/QuikGraph.Tests/Misc/CryptoRandomTests.cs b/tests/QuikGraph.Tests/Misc/CryptoRandomTests.cs index 81c9a2328..38ff5f312 100644 --- a/tests/QuikGraph.Tests/Misc/CryptoRandomTests.cs +++ b/tests/QuikGraph.Tests/Misc/CryptoRandomTests.cs @@ -1,5 +1,4 @@ -#if SUPPORTS_CRYPTO_RANDOM -using System; +using System; using NUnit.Framework; using QuikGraph.Utils; @@ -113,5 +112,4 @@ public void NextBytes_Throws() Assert.Throws(() => rng.NextBytes(null)); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/tests/QuikGraph.Tests/QuikGraph.Tests.csproj b/tests/QuikGraph.Tests/QuikGraph.Tests.csproj index 059ef0ddb..d209a13c9 100644 --- a/tests/QuikGraph.Tests/QuikGraph.Tests.csproj +++ b/tests/QuikGraph.Tests/QuikGraph.Tests.csproj @@ -20,40 +20,40 @@ - $(DefineConstants);NET35;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) + $(DefineConstants);NET35;SUPPORTS_SERIALIZATION;$(AdditionalConstants) - $(DefineConstants);NET40;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) + $(DefineConstants);NET40;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;$(AdditionalConstants) - $(DefineConstants);NET45;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET45;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET451;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET451;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET452;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET452;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET46;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET46;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET461;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET461;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET462;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET462;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET47;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET47;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET471;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET471;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NET472;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;SUPPORTS_TASKS;$(AdditionalConstants) + $(DefineConstants);NET472;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - $(DefineConstants);NETCOREAPP2_1;SUPPORTS_SERIALIZATION;SUPPORTS_CLONEABLE;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_CONVERTER;SUPPORTS_TYPE_FULL_FEATURES;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_XML_DTD_PROCESSING;SUPPORTS_CRYPTO_RANDOM;$(AdditionalConstants) + $(DefineConstants);NETCOREAPP2_1;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;$(AdditionalConstants) From 6519d40b52740cf85a1ad0dfa0d7d74e965bfc96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 27 Mar 2022 23:03:36 +0200 Subject: [PATCH 26/39] Add cycle checking for edge set and undirected graphs. Fix #58 --- .../Extensions/AlgorithmExtensions.cs | 138 +++++++++++- src/QuikGraph/Extensions/EdgeExtensions.cs | 2 +- .../Extensions/AlgorithmExtensionsTests.cs | 199 +++++++++++++++++- 3 files changed, 321 insertions(+), 18 deletions(-) diff --git a/src/QuikGraph/Extensions/AlgorithmExtensions.cs b/src/QuikGraph/Extensions/AlgorithmExtensions.cs index b0d85a714..e446e1ba8 100644 --- a/src/QuikGraph/Extensions/AlgorithmExtensions.cs +++ b/src/QuikGraph/Extensions/AlgorithmExtensions.cs @@ -7,6 +7,9 @@ #else using QuikGraph.Utils; #endif +#if SUPPORTS_AGGRESSIVE_INLINING +using System.Runtime.CompilerServices; +#endif using JetBrains.Annotations; using QuikGraph.Algorithms.Condensation; using QuikGraph.Algorithms.ConnectedComponents; @@ -898,10 +901,75 @@ public static IEnumerable OddVertices( .Select(pair => pair.Key); } + private sealed class DirectedCycleTester + where TEdge : IEdge + { + private bool _isDag = true; + + [Pure] + public bool IsDag([NotNull] IVertexListGraph graph) + { + Debug.Assert(graph != null); + + var dfs = new DepthFirstSearchAlgorithm(graph); + try + { + dfs.BackEdge += DfsBackEdge; + _isDag = true; + dfs.Compute(); + return _isDag; + } + finally + { + dfs.BackEdge -= DfsBackEdge; + } + } + + private void DfsBackEdge([NotNull] TEdge edge) + { + _isDag = false; + } + } + + [Pure] +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private static bool IsDirectedAcyclicGraphInternal( + [NotNull] this IVertexListGraph graph) + where TEdge : IEdge + { + return new DirectedCycleTester().IsDag(graph); + } + /// /// Checks whether the graph is acyclic or not. /// /// + /// Builds an from + /// and performs a depth first search to look for cycles. + /// + /// Vertex type. + /// Edge type. + /// Edges of forming the graph to visit. + /// True if the graph contains a cycle, false otherwise. + /// + /// is or at least one of them is . + /// + [Pure] + public static bool IsDirectedAcyclicGraph( + [NotNull, ItemNotNull] this IEnumerable edges) + where TEdge : IEdge + { + var graph = new AdjacencyGraph(); + graph.AddVerticesAndEdgeRange(edges); + return IsDirectedAcyclicGraphInternal(graph); + } + + /// + /// Checks whether the is acyclic or not. + /// + /// /// Performs a depth first search to look for cycles. /// /// Vertex type. @@ -916,26 +984,25 @@ public static bool IsDirectedAcyclicGraph( { if (graph is null) throw new ArgumentNullException(nameof(graph)); - return new DagTester().IsDag(graph); + return IsDirectedAcyclicGraphInternal(graph); } - private sealed class DagTester + private sealed class UndirectedCycleTester where TEdge : IEdge { - private bool _isDag = true; + private bool _hasCycle; [Pure] - public bool IsDag([NotNull] IVertexListGraph graph) + public bool HasCycle([NotNull] IUndirectedGraph graph) { Debug.Assert(graph != null); - var dfs = new DepthFirstSearchAlgorithm(graph); + var dfs = new UndirectedDepthFirstSearchAlgorithm(graph); try { dfs.BackEdge += DfsBackEdge; - _isDag = true; dfs.Compute(); - return _isDag; + return _hasCycle; } finally { @@ -943,12 +1010,65 @@ public bool IsDag([NotNull] IVertexListGraph graph) } } - private void DfsBackEdge([NotNull] TEdge edge) + private void DfsBackEdge([NotNull] object sender, [NotNull] UndirectedEdgeEventArgs args) { - _isDag = false; + _hasCycle = true; } } + [Pure] +#if SUPPORTS_AGGRESSIVE_INLINING + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private static bool IsUndirectedAcyclicGraphInternal( + [NotNull] this IUndirectedGraph graph) + where TEdge : IEdge + { + return !new UndirectedCycleTester().HasCycle(graph); + } + + /// + /// Checks whether the graph is acyclic or not. + /// + /// + /// Builds an from + /// and performs a depth first search to look for cycles. + /// + /// Vertex type. + /// Edge type. + /// Edges of forming the graph to visit. + /// True if the graph contains a cycle, false otherwise. + /// + /// is or at least one of them is . + /// + [Pure] + public static bool IsUndirectedAcyclicGraph( + [NotNull, ItemNotNull] this IEnumerable edges) + where TEdge : IEdge + { + var graph = new UndirectedGraph(); + graph.AddVerticesAndEdgeRange(edges); + return IsUndirectedAcyclicGraphInternal(graph); + } + + /// + /// Checks whether the is acyclic or not. + /// + /// Vertex type. + /// Edge type. + /// Graph to visit. + /// True if the graph contains a cycle, false otherwise. + /// is . + [Pure] + public static bool IsUndirectedAcyclicGraph( + [NotNull] this IUndirectedGraph graph) + where TEdge : IEdge + { + if (graph is null) + throw new ArgumentNullException(nameof(graph)); + return IsUndirectedAcyclicGraphInternal(graph); + } + /// /// Given a edge cost map, computes the corresponding predecessor costs. /// diff --git a/src/QuikGraph/Extensions/EdgeExtensions.cs b/src/QuikGraph/Extensions/EdgeExtensions.cs index 97d09fbcd..38b99ce15 100644 --- a/src/QuikGraph/Extensions/EdgeExtensions.cs +++ b/src/QuikGraph/Extensions/EdgeExtensions.cs @@ -114,7 +114,7 @@ public static bool IsPath([NotNull, ItemNotNull] this IEnumerabl /// Note that this function only work when given a path. /// Vertex type. /// Edge type. - /// Sequence of edges. + /// Sequence of edges that forms a path. /// True if the set makes a cycle, false otherwise. /// is . [Pure] diff --git a/tests/QuikGraph.Tests/Extensions/AlgorithmExtensionsTests.cs b/tests/QuikGraph.Tests/Extensions/AlgorithmExtensionsTests.cs index 593d45bdb..e89780826 100644 --- a/tests/QuikGraph.Tests/Extensions/AlgorithmExtensionsTests.cs +++ b/tests/QuikGraph.Tests/Extensions/AlgorithmExtensionsTests.cs @@ -1457,23 +1457,51 @@ private static IEnumerable CreateIsDirectedAcyclicGraphTestCases( }; var edge12 = new Edge(1, 2); + var edge13 = new Edge(1, 3); var edge14 = new Edge(1, 4); + var edge16 = new Edge(1, 6); + var edge22 = new Edge(2, 2); var edge23 = new Edge(2, 3); var edge24 = new Edge(2, 4); + var edge25 = new Edge(2, 5); + var edge31 = new Edge(3, 1); + var edge34 = new Edge(3, 4); + var edge35 = new Edge(3, 5); + var edge41 = new Edge(4, 1); + var edge44 = new Edge(4, 4); + var edge52 = new Edge(5, 2); + var edge56 = new Edge(5, 6); // Not empty acyclic - var adjacencyGraph = createGraph(); - adjacencyGraph.AddVerticesAndEdgeRange(new[] + var adjacencyGraph1 = createGraph(); + adjacencyGraph1.AddVertexRange(new[] { 1, 2, 3 }); + yield return new TestCaseData(adjacencyGraph1) + { + ExpectedResult = true + }; + + var adjacencyGraph2 = createGraph(); + adjacencyGraph2.AddVerticesAndEdgeRange(new[] { edge12, edge14, edge23, edge24 }); - yield return new TestCaseData(adjacencyGraph) + yield return new TestCaseData(adjacencyGraph2) + { + ExpectedResult = true + }; + + var adjacencyGraph3 = createGraph(); + adjacencyGraph3.AddVertex(0); + adjacencyGraph3.AddVerticesAndEdgeRange(new[] + { + edge12, edge14, edge23, edge56 + }); + yield return new TestCaseData(adjacencyGraph3) { ExpectedResult = true }; // Not acyclic - var edge22 = new Edge(2, 2); var cyclicGraph1 = createGraph(); cyclicGraph1.AddVerticesAndEdge(edge22); yield return new TestCaseData(cyclicGraph1) @@ -1491,7 +1519,6 @@ private static IEnumerable CreateIsDirectedAcyclicGraphTestCases( ExpectedResult = false }; - var edge41 = new Edge(4, 1); var cyclicGraph3 = createGraph(); cyclicGraph3.AddVerticesAndEdgeRange(new[] { @@ -1501,6 +1528,27 @@ private static IEnumerable CreateIsDirectedAcyclicGraphTestCases( { ExpectedResult = false }; + + var cyclicGraph4 = createGraph(); + cyclicGraph4.AddVerticesAndEdgeRange(new[] + { + edge12, edge13, edge23, edge31, edge34, edge44 + }); + yield return new TestCaseData(cyclicGraph4) + { + ExpectedResult = false + }; + + var cyclicGraph5 = createGraph(); + cyclicGraph5.AddVertex(0); + cyclicGraph5.AddVerticesAndEdgeRange(new[] + { + edge16, edge23, edge25, edge34, edge35, edge52 + }); + yield return new TestCaseData(cyclicGraph5) + { + ExpectedResult = false + }; } [NotNull, ItemNotNull] @@ -1519,18 +1567,153 @@ private static IEnumerable IsDirectedAcyclicGraphTestCases } [TestCaseSource(nameof(IsDirectedAcyclicGraphTestCases))] - public bool IsDirectedAcyclicGraph([NotNull] IVertexListGraph> graph) + public bool IsDirectedAcyclicGraph([NotNull] IVertexAndEdgeListGraph> graph) { return graph.IsDirectedAcyclicGraph(); } + [TestCaseSource(nameof(IsDirectedAcyclicGraphTestCases))] + public bool IsDirectedAcyclicGraph_FromEdges([NotNull] IVertexAndEdgeListGraph> graph) + { + return graph.Edges.IsDirectedAcyclicGraph>(); + } + [Test] public void IsDirectedAcyclicGraph_Throws() { - // ReSharper disable once ReturnValueOfPureMethodIsNotUsed - // ReSharper disable once AssignNullToNotNullAttribute + // ReSharper disable ReturnValueOfPureMethodIsNotUsed + // ReSharper disable AssignNullToNotNullAttribute Assert.Throws( () => ((AdjacencyGraph>)null).IsDirectedAcyclicGraph()); + + Assert.Throws( + () => ((IEnumerable>)null).IsDirectedAcyclicGraph>()); + var edges = new[] { new Edge(1, 2), null, new Edge(1, 3) }; + Assert.Throws( + () => edges.IsDirectedAcyclicGraph>()); + // ReSharper restore AssignNullToNotNullAttribute + // ReSharper restore ReturnValueOfPureMethodIsNotUsed + } + + [NotNull, ItemNotNull] + private static IEnumerable IsUndirectedAcyclicGraphTestCases + { + [UsedImplicitly] + get + { + // Empty graph + yield return new TestCaseData(new UndirectedGraph>()) + { + ExpectedResult = true + }; + + var edge12 = new Edge(1, 2); + var edge14 = new Edge(1, 4); + var edge16 = new Edge(1, 6); + var edge22 = new Edge(2, 2); + var edge23 = new Edge(2, 3); + var edge24 = new Edge(2, 4); + var edge25 = new Edge(2, 5); + var edge35 = new Edge(3, 5); + var edge56 = new Edge(5, 6); + + // Not empty acyclic + var undirectedGraph1 = new UndirectedGraph>(); + undirectedGraph1.AddVertexRange(new[] { 1, 2, 3 }); + yield return new TestCaseData(undirectedGraph1) + { + ExpectedResult = true + }; + + var undirectedGraph2 = new UndirectedGraph>(); + undirectedGraph2.AddVerticesAndEdgeRange(new[] + { + edge12, edge23, edge24 + }); + yield return new TestCaseData(undirectedGraph2) + { + ExpectedResult = true + }; + + var undirectedGraph3 = new UndirectedGraph>(); + undirectedGraph3.AddVertex(0); + undirectedGraph3.AddVerticesAndEdgeRange(new[] + { + edge12, edge14, edge23, edge56 + }); + yield return new TestCaseData(undirectedGraph3) + { + ExpectedResult = true + }; + + // Not acyclic + var cyclicGraph1 = new UndirectedGraph>(); + cyclicGraph1.AddVerticesAndEdge(edge22); + yield return new TestCaseData(cyclicGraph1) + { + ExpectedResult = false + }; + + var cyclicGraph2 = new UndirectedGraph>(); + cyclicGraph2.AddVerticesAndEdgeRange(new[] + { + edge12, edge14, edge22, edge23, edge24 + }); + yield return new TestCaseData(cyclicGraph2) + { + ExpectedResult = false + }; + + var cyclicGraph3 = new UndirectedGraph>(); + cyclicGraph3.AddVerticesAndEdgeRange(new[] + { + edge12, edge14, edge23, edge24 + }); + yield return new TestCaseData(cyclicGraph3) + { + ExpectedResult = false + }; + + var cyclicGraph4 = new UndirectedGraph>(); + cyclicGraph4.AddVertex(0); + cyclicGraph4.AddVerticesAndEdgeRange(new[] + { + edge16, edge23, edge25, edge35 + }); + yield return new TestCaseData(cyclicGraph4) + { + ExpectedResult = false + }; + } + } + + [TestCaseSource(nameof(IsUndirectedAcyclicGraphTestCases))] + public bool IsUndirectedAcyclicGraph([NotNull] IUndirectedGraph> graph) + { + return graph.IsUndirectedAcyclicGraph(); + } + + [TestCaseSource(nameof(IsUndirectedAcyclicGraphTestCases))] + public bool IsUndirectedAcyclicGraph_FromEdges([NotNull] IUndirectedGraph> graph) + { + return graph.Edges.IsUndirectedAcyclicGraph>(); + } + + [Test] + public void IsUndirectedAcyclicGraph_Throws() + { + // ReSharper disable ReturnValueOfPureMethodIsNotUsed + // ReSharper disable AssignNullToNotNullAttribute + Assert.Throws( + () => ((UndirectedGraph>)null).IsUndirectedAcyclicGraph()); + + Assert.Throws( + () => ((IEnumerable>)null).IsUndirectedAcyclicGraph>()); + var edges = new[] { new Edge(1, 2), null, new Edge(1, 3) }; + Assert.Throws( + () => edges.IsUndirectedAcyclicGraph>()); + // ReSharper restore AssignNullToNotNullAttribute + // ReSharper restore ReturnValueOfPureMethodIsNotUsed } [Test] From f28a9d3087947427ed4323ae20c08bbc5eb2253d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 28 Mar 2022 21:08:38 +0200 Subject: [PATCH 27/39] Upgrade tests to netcoreapp3.1 (supported framework). --- tests/QuikGraph.Data.Tests/QuikGraph.Data.Tests.csproj | 6 +++--- tests/QuikGraph.Graphviz.Tests/GraphvizAlgorithmTests.cs | 1 + .../QuikGraph.Graphviz.Tests.csproj | 6 +++--- tests/QuikGraph.MSAGL.Tests/MsaglGraphPopulatorTestsBase.cs | 1 + tests/QuikGraph.MSAGL.Tests/QuikGraph.MSAGL.Tests.csproj | 6 +++--- tests/QuikGraph.Petri.Tests/QuikGraph.Petri.Tests.csproj | 6 +++--- .../QuikGraph.Serialization.Tests.csproj | 6 +++--- .../TestClasses/SerializationTestEdgeClasses.cs | 2 +- .../TestClasses/SerializationTestVertexClasses.cs | 2 +- tests/QuikGraph.Tests.CommonInternals/QuikGraphAssert.cs | 3 ++- tests/QuikGraph.Tests/QuikGraph.Tests.csproj | 6 +++--- 11 files changed, 24 insertions(+), 21 deletions(-) diff --git a/tests/QuikGraph.Data.Tests/QuikGraph.Data.Tests.csproj b/tests/QuikGraph.Data.Tests/QuikGraph.Data.Tests.csproj index 4a2068e4e..e581b0ba5 100644 --- a/tests/QuikGraph.Data.Tests/QuikGraph.Data.Tests.csproj +++ b/tests/QuikGraph.Data.Tests/QuikGraph.Data.Tests.csproj @@ -1,7 +1,7 @@ - net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp2.1 + net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp3.1 QuikGraph.Data.Tests @@ -47,8 +47,8 @@ $(DefineConstants);NET472;$(AdditionalConstants) - - $(DefineConstants);NETCOREAPP2_1;$(AdditionalConstants) + + $(DefineConstants);NETCOREAPP3_1;$(AdditionalConstants) diff --git a/tests/QuikGraph.Graphviz.Tests/GraphvizAlgorithmTests.cs b/tests/QuikGraph.Graphviz.Tests/GraphvizAlgorithmTests.cs index 9a1312c46..02a8efc73 100644 --- a/tests/QuikGraph.Graphviz.Tests/GraphvizAlgorithmTests.cs +++ b/tests/QuikGraph.Graphviz.Tests/GraphvizAlgorithmTests.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using NUnit.Framework; using QuikGraph.Graphviz.Dot; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; namespace QuikGraph.Graphviz.Tests { diff --git a/tests/QuikGraph.Graphviz.Tests/QuikGraph.Graphviz.Tests.csproj b/tests/QuikGraph.Graphviz.Tests/QuikGraph.Graphviz.Tests.csproj index 71171bc2c..83b8fb018 100644 --- a/tests/QuikGraph.Graphviz.Tests/QuikGraph.Graphviz.Tests.csproj +++ b/tests/QuikGraph.Graphviz.Tests/QuikGraph.Graphviz.Tests.csproj @@ -1,7 +1,7 @@ - net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp2.1 + net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp3.1 QuikGraph.Graphviz.Tests @@ -47,8 +47,8 @@ $(DefineConstants);NET472;SUPPORTS_FONT;$(AdditionalConstants) - - $(DefineConstants);NETCOREAPP2_1;$(AdditionalConstants) + + $(DefineConstants);NETCOREAPP3_1;$(AdditionalConstants) diff --git a/tests/QuikGraph.MSAGL.Tests/MsaglGraphPopulatorTestsBase.cs b/tests/QuikGraph.MSAGL.Tests/MsaglGraphPopulatorTestsBase.cs index bf98bc1c2..12f58ccde 100644 --- a/tests/QuikGraph.MSAGL.Tests/MsaglGraphPopulatorTestsBase.cs +++ b/tests/QuikGraph.MSAGL.Tests/MsaglGraphPopulatorTestsBase.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using NUnit.Framework; using static QuikGraph.MSAGL.Tests.MsaglGraphTestHelpers; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; namespace QuikGraph.MSAGL.Tests { diff --git a/tests/QuikGraph.MSAGL.Tests/QuikGraph.MSAGL.Tests.csproj b/tests/QuikGraph.MSAGL.Tests/QuikGraph.MSAGL.Tests.csproj index 185453dee..6ff93c854 100644 --- a/tests/QuikGraph.MSAGL.Tests/QuikGraph.MSAGL.Tests.csproj +++ b/tests/QuikGraph.MSAGL.Tests/QuikGraph.MSAGL.Tests.csproj @@ -1,7 +1,7 @@ - net461;net462;net47;net471;net472;netcoreapp2.1 + net461;net462;net47;net471;net472;netcoreapp3.1 QuikGraph.MSAGL.Tests @@ -29,8 +29,8 @@ $(DefineConstants);NET472;$(AdditionalConstants) - - $(DefineConstants);NETCOREAPP2_1;$(AdditionalConstants) + + $(DefineConstants);NETCOREAPP3_1;$(AdditionalConstants) diff --git a/tests/QuikGraph.Petri.Tests/QuikGraph.Petri.Tests.csproj b/tests/QuikGraph.Petri.Tests/QuikGraph.Petri.Tests.csproj index 8baf53284..0b6d5a3d3 100644 --- a/tests/QuikGraph.Petri.Tests/QuikGraph.Petri.Tests.csproj +++ b/tests/QuikGraph.Petri.Tests/QuikGraph.Petri.Tests.csproj @@ -1,7 +1,7 @@ - net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp2.1 + net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp3.1 QuikGraph.Petri.Tests @@ -52,8 +52,8 @@ $(DefineConstants);NET472;$(AdditionalConstants) - - $(DefineConstants);NETCOREAPP2_1;$(AdditionalConstants) + + $(DefineConstants);NETCOREAPP3_1;$(AdditionalConstants) diff --git a/tests/QuikGraph.Serialization.Tests/QuikGraph.Serialization.Tests.csproj b/tests/QuikGraph.Serialization.Tests/QuikGraph.Serialization.Tests.csproj index 8b2cd09f5..82c1c0bc9 100644 --- a/tests/QuikGraph.Serialization.Tests/QuikGraph.Serialization.Tests.csproj +++ b/tests/QuikGraph.Serialization.Tests/QuikGraph.Serialization.Tests.csproj @@ -1,7 +1,7 @@ - net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp2.1 + net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp3.1 QuikGraph.Serialization.Tests @@ -52,8 +52,8 @@ $(DefineConstants);NET472;SUPPORTS_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) - - $(DefineConstants);NETCOREAPP2_1;SUPPORTS_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) + + $(DefineConstants);NETCOREAPP3_1;SUPPORTS_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) diff --git a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs index df645b851..9517ce1a6 100644 --- a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs +++ b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Xml.Serialization; -using JetBrains.Annotations; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; namespace QuikGraph.Serialization.Tests { diff --git a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs index 82ff7d798..57d6b950f 100644 --- a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs +++ b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs @@ -3,7 +3,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Xml.Serialization; -using JetBrains.Annotations; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; namespace QuikGraph.Serialization.Tests { diff --git a/tests/QuikGraph.Tests.CommonInternals/QuikGraphAssert.cs b/tests/QuikGraph.Tests.CommonInternals/QuikGraphAssert.cs index fc448ec52..a85322cbb 100644 --- a/tests/QuikGraph.Tests.CommonInternals/QuikGraphAssert.cs +++ b/tests/QuikGraph.Tests.CommonInternals/QuikGraphAssert.cs @@ -1,8 +1,9 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; using NUnit.Framework; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; namespace QuikGraph.Tests { diff --git a/tests/QuikGraph.Tests/QuikGraph.Tests.csproj b/tests/QuikGraph.Tests/QuikGraph.Tests.csproj index d209a13c9..73e70dd4a 100644 --- a/tests/QuikGraph.Tests/QuikGraph.Tests.csproj +++ b/tests/QuikGraph.Tests/QuikGraph.Tests.csproj @@ -1,7 +1,7 @@ - net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp2.1 + net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netcoreapp3.1 QuikGraph.Tests @@ -52,8 +52,8 @@ $(DefineConstants);NET472;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;SUPPORTS_TASKS;$(AdditionalConstants) - - $(DefineConstants);NETCOREAPP2_1;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;$(AdditionalConstants) + + $(DefineConstants);NETCOREAPP3_1;SUPPORTS_SERIALIZATION;SUPPORTS_SORTEDSET;SUPPORTS_ENUMERABLE_COVARIANT;$(AdditionalConstants) From 3f3f0432930b3b426945dab5a7c8bb17d64c63fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Thu, 23 Jun 2022 23:07:19 +0200 Subject: [PATCH 28/39] Move files to a dedicated folder by kind of serialization. --- .../DirectedGraphMLAlgorithm.cs | 0 .../DirectedGraphMLExtensions.cs | 0 .../{ => GraphML}/GraphMLDeserializer.cs | 0 .../{ => GraphML}/GraphMLExtensions.cs | 5 +--- .../GraphML/GraphMLResourceResolver.cs | 29 +++++++++++++++++++ .../{ => GraphML}/GraphMLSerializer.cs | 0 .../{ => GraphML}/GraphMLXmlResolver.cs | 20 ++----------- .../{ => GraphML}/SerializerBase.cs | 0 .../{ => GraphML}/XmlReaderExtensions.cs | 0 .../{ => GraphML}/XmlWriterExtensions.cs | 0 .../{ => GraphML}/graphml-attributes.xsd | 0 .../{ => GraphML}/graphml-parseinfo.xsd | 0 .../{ => GraphML}/graphml-structure.xsd | 0 .../{ => GraphML}/graphml.dtd | 0 .../{ => GraphML}/graphml.xsd | 0 .../{ => GraphML}/xlink.xsd | 0 .../QuikGraph.Serialization.csproj | 8 ++--- .../{ => XML}/XmlConstants.cs | 0 .../{ => XML}/XmlSerializableEdge.cs | 0 .../{ => XML}/XmlSerializableGraph.cs | 0 20 files changed, 34 insertions(+), 28 deletions(-) rename src/QuikGraph.Serialization/{ => DirectedGraphML}/DirectedGraphMLAlgorithm.cs (100%) rename src/QuikGraph.Serialization/{ => DirectedGraphML}/DirectedGraphMLExtensions.cs (100%) rename src/QuikGraph.Serialization/{ => GraphML}/GraphMLDeserializer.cs (100%) rename src/QuikGraph.Serialization/{ => GraphML}/GraphMLExtensions.cs (98%) create mode 100644 src/QuikGraph.Serialization/GraphML/GraphMLResourceResolver.cs rename src/QuikGraph.Serialization/{ => GraphML}/GraphMLSerializer.cs (100%) rename src/QuikGraph.Serialization/{ => GraphML}/GraphMLXmlResolver.cs (83%) rename src/QuikGraph.Serialization/{ => GraphML}/SerializerBase.cs (100%) rename src/QuikGraph.Serialization/{ => GraphML}/XmlReaderExtensions.cs (100%) rename src/QuikGraph.Serialization/{ => GraphML}/XmlWriterExtensions.cs (100%) rename src/QuikGraph.Serialization/{ => GraphML}/graphml-attributes.xsd (100%) rename src/QuikGraph.Serialization/{ => GraphML}/graphml-parseinfo.xsd (100%) rename src/QuikGraph.Serialization/{ => GraphML}/graphml-structure.xsd (100%) rename src/QuikGraph.Serialization/{ => GraphML}/graphml.dtd (100%) rename src/QuikGraph.Serialization/{ => GraphML}/graphml.xsd (100%) rename src/QuikGraph.Serialization/{ => GraphML}/xlink.xsd (100%) rename src/QuikGraph.Serialization/{ => XML}/XmlConstants.cs (100%) rename src/QuikGraph.Serialization/{ => XML}/XmlSerializableEdge.cs (100%) rename src/QuikGraph.Serialization/{ => XML}/XmlSerializableGraph.cs (100%) diff --git a/src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs b/src/QuikGraph.Serialization/DirectedGraphML/DirectedGraphMLAlgorithm.cs similarity index 100% rename from src/QuikGraph.Serialization/DirectedGraphMLAlgorithm.cs rename to src/QuikGraph.Serialization/DirectedGraphML/DirectedGraphMLAlgorithm.cs diff --git a/src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs b/src/QuikGraph.Serialization/DirectedGraphML/DirectedGraphMLExtensions.cs similarity index 100% rename from src/QuikGraph.Serialization/DirectedGraphMLExtensions.cs rename to src/QuikGraph.Serialization/DirectedGraphML/DirectedGraphMLExtensions.cs diff --git a/src/QuikGraph.Serialization/GraphMLDeserializer.cs b/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs similarity index 100% rename from src/QuikGraph.Serialization/GraphMLDeserializer.cs rename to src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs diff --git a/src/QuikGraph.Serialization/GraphMLExtensions.cs b/src/QuikGraph.Serialization/GraphML/GraphMLExtensions.cs similarity index 98% rename from src/QuikGraph.Serialization/GraphMLExtensions.cs rename to src/QuikGraph.Serialization/GraphML/GraphMLExtensions.cs index e912e3345..a7f238904 100644 --- a/src/QuikGraph.Serialization/GraphMLExtensions.cs +++ b/src/QuikGraph.Serialization/GraphML/GraphMLExtensions.cs @@ -1,7 +1,6 @@ #if SUPPORTS_GRAPHS_SERIALIZATION using System; #if SUPPORTS_XML_DTD_PROCESSING -using System.Diagnostics; using System.Xml.Schema; #endif using System.IO; @@ -324,10 +323,8 @@ public static void DeserializeAndValidateFromGraphML( private static void AddGraphMLSchema([NotNull] XmlReaderSettings settings, [NotNull] XmlResolver resolver) { - using (Stream xsdStream = typeof(GraphMLExtensions).Assembly.GetManifestResourceStream(typeof(GraphMLExtensions), "graphml.xsd")) + using (Stream xsdStream = GraphMLResourceResolver.GetResource("graphml.xsd")) { - Debug.Assert(xsdStream != null, "GraphML schema resource not found."); - settings.Schemas.XmlResolver = resolver; // ReSharper disable once AssignNullToNotNullAttribute, Justification: assert above using (XmlReader xsdReader = XmlReader.Create(xsdStream, settings)) diff --git a/src/QuikGraph.Serialization/GraphML/GraphMLResourceResolver.cs b/src/QuikGraph.Serialization/GraphML/GraphMLResourceResolver.cs new file mode 100644 index 000000000..c2f22970a --- /dev/null +++ b/src/QuikGraph.Serialization/GraphML/GraphMLResourceResolver.cs @@ -0,0 +1,29 @@ +#if SUPPORTS_GRAPHS_SERIALIZATION +using System.Diagnostics; +using System.IO; +using JetBrains.Annotations; + +namespace QuikGraph.Serialization +{ + internal static class GraphMLResourceResolver + { + /// + /// Gets the GraphML resource with given . + /// + /// Resource name. + /// Resource stream. + [Pure] + [NotNull] + public static Stream GetResource([NotNull] string resourceName) + { + Stream resourceStream = typeof(GraphMLResourceResolver).Assembly + .GetManifestResourceStream( + typeof(GraphMLResourceResolver), + $@"GraphML.{resourceName}"); + + Debug.Assert(resourceStream != null); + return resourceStream; + } + } +} +#endif \ No newline at end of file diff --git a/src/QuikGraph.Serialization/GraphMLSerializer.cs b/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs similarity index 100% rename from src/QuikGraph.Serialization/GraphMLSerializer.cs rename to src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs diff --git a/src/QuikGraph.Serialization/GraphMLXmlResolver.cs b/src/QuikGraph.Serialization/GraphML/GraphMLXmlResolver.cs similarity index 83% rename from src/QuikGraph.Serialization/GraphMLXmlResolver.cs rename to src/QuikGraph.Serialization/GraphML/GraphMLXmlResolver.cs index 4f40f3337..dd391db80 100644 --- a/src/QuikGraph.Serialization/GraphMLXmlResolver.cs +++ b/src/QuikGraph.Serialization/GraphML/GraphMLXmlResolver.cs @@ -1,10 +1,9 @@ #if SUPPORTS_GRAPHS_SERIALIZATION using System; -using System.Diagnostics; -using System.IO; using System.Net; using System.Xml; using JetBrains.Annotations; +using static QuikGraph.Serialization.GraphMLResourceResolver; namespace QuikGraph.Serialization { @@ -71,23 +70,8 @@ public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToRe if (absoluteUri.AbsoluteUri.EndsWith("xlink.xsd")) return GetResource("xlink.xsd"); - - return _baseResolver.GetEntity(absoluteUri, role, ofObjectToReturn); - #region Local function - - Stream GetResource(string resourceName) - { - Stream resourceStream = typeof(GraphMLExtensions).Assembly - .GetManifestResourceStream( - typeof(GraphMLExtensions), - resourceName); - - Debug.Assert(resourceStream != null); - return resourceStream; - } - - #endregion + return _baseResolver.GetEntity(absoluteUri, role, ofObjectToReturn); } } } diff --git a/src/QuikGraph.Serialization/SerializerBase.cs b/src/QuikGraph.Serialization/GraphML/SerializerBase.cs similarity index 100% rename from src/QuikGraph.Serialization/SerializerBase.cs rename to src/QuikGraph.Serialization/GraphML/SerializerBase.cs diff --git a/src/QuikGraph.Serialization/XmlReaderExtensions.cs b/src/QuikGraph.Serialization/GraphML/XmlReaderExtensions.cs similarity index 100% rename from src/QuikGraph.Serialization/XmlReaderExtensions.cs rename to src/QuikGraph.Serialization/GraphML/XmlReaderExtensions.cs diff --git a/src/QuikGraph.Serialization/XmlWriterExtensions.cs b/src/QuikGraph.Serialization/GraphML/XmlWriterExtensions.cs similarity index 100% rename from src/QuikGraph.Serialization/XmlWriterExtensions.cs rename to src/QuikGraph.Serialization/GraphML/XmlWriterExtensions.cs diff --git a/src/QuikGraph.Serialization/graphml-attributes.xsd b/src/QuikGraph.Serialization/GraphML/graphml-attributes.xsd similarity index 100% rename from src/QuikGraph.Serialization/graphml-attributes.xsd rename to src/QuikGraph.Serialization/GraphML/graphml-attributes.xsd diff --git a/src/QuikGraph.Serialization/graphml-parseinfo.xsd b/src/QuikGraph.Serialization/GraphML/graphml-parseinfo.xsd similarity index 100% rename from src/QuikGraph.Serialization/graphml-parseinfo.xsd rename to src/QuikGraph.Serialization/GraphML/graphml-parseinfo.xsd diff --git a/src/QuikGraph.Serialization/graphml-structure.xsd b/src/QuikGraph.Serialization/GraphML/graphml-structure.xsd similarity index 100% rename from src/QuikGraph.Serialization/graphml-structure.xsd rename to src/QuikGraph.Serialization/GraphML/graphml-structure.xsd diff --git a/src/QuikGraph.Serialization/graphml.dtd b/src/QuikGraph.Serialization/GraphML/graphml.dtd similarity index 100% rename from src/QuikGraph.Serialization/graphml.dtd rename to src/QuikGraph.Serialization/GraphML/graphml.dtd diff --git a/src/QuikGraph.Serialization/graphml.xsd b/src/QuikGraph.Serialization/GraphML/graphml.xsd similarity index 100% rename from src/QuikGraph.Serialization/graphml.xsd rename to src/QuikGraph.Serialization/GraphML/graphml.xsd diff --git a/src/QuikGraph.Serialization/xlink.xsd b/src/QuikGraph.Serialization/GraphML/xlink.xsd similarity index 100% rename from src/QuikGraph.Serialization/xlink.xsd rename to src/QuikGraph.Serialization/GraphML/xlink.xsd diff --git a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj index 58f6e2572..663bd2f8d 100644 --- a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj +++ b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj @@ -35,12 +35,8 @@ Updates: - - - - - - + + diff --git a/src/QuikGraph.Serialization/XmlConstants.cs b/src/QuikGraph.Serialization/XML/XmlConstants.cs similarity index 100% rename from src/QuikGraph.Serialization/XmlConstants.cs rename to src/QuikGraph.Serialization/XML/XmlConstants.cs diff --git a/src/QuikGraph.Serialization/XmlSerializableEdge.cs b/src/QuikGraph.Serialization/XML/XmlSerializableEdge.cs similarity index 100% rename from src/QuikGraph.Serialization/XmlSerializableEdge.cs rename to src/QuikGraph.Serialization/XML/XmlSerializableEdge.cs diff --git a/src/QuikGraph.Serialization/XmlSerializableGraph.cs b/src/QuikGraph.Serialization/XML/XmlSerializableGraph.cs similarity index 100% rename from src/QuikGraph.Serialization/XmlSerializableGraph.cs rename to src/QuikGraph.Serialization/XML/XmlSerializableGraph.cs From 0353ab196597e97762c02f002bdcd75d59263a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sat, 25 Jun 2022 15:51:54 +0200 Subject: [PATCH 29/39] Fix fields being written several type for type with multiple inheritance layers. --- src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs b/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs index 27233df8d..9ff89d276 100644 --- a/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs +++ b/src/QuikGraph.Serialization/Helpers/SerializationHelpers.cs @@ -50,7 +50,7 @@ public static IEnumerable GetAttributeProperties([Can { // Iterate through properties that must have a get, and are not indexed property IEnumerable properties = currentType - .GetProperties(BindingFlags.Public | BindingFlags.Instance) + .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) .Where(ValidProperty); foreach (PropertyInfo property in properties) { From a61a06f8d3e1f8bc65cd77add615edd0a42a24c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sat, 25 Jun 2022 16:06:59 +0200 Subject: [PATCH 30/39] Optimize a bit methods calls in generated code for GraphML serialization. --- .../GraphML/GraphMLDeserializer.cs | 18 ++++---------- .../GraphML/GraphMLSerializer.cs | 24 +++++-------------- .../Helpers/ILHelpers.cs | 14 +++++------ 3 files changed, 18 insertions(+), 38 deletions(-) diff --git a/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs b/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs index 5ba033d36..61bb7e5ed 100644 --- a/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs +++ b/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs @@ -177,7 +177,7 @@ private static Delegate CreateReadDelegate( generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldstr, "key"); - generator.EmitCall(OpCodes.Callvirt, Metadata.GetAttributeMethod, null); + EmitCall(generator, Metadata.GetAttributeMethod); generator.Emit(OpCodes.Stloc_0); // We need to create the switch for each property @@ -196,7 +196,7 @@ private static Delegate CreateReadDelegate( generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldstr, info.Name); - generator.EmitCall(OpCodes.Call, Metadata.StringEqualsMethod, null); + EmitCall(generator, Metadata.StringEqualsMethod); // If false jump to next generator.Emit(OpCodes.Brfalse, next); @@ -210,21 +210,13 @@ private static Delegate CreateReadDelegate( if (setMethod is null) throw new InvalidOperationException($"Property {property.DeclaringType}.{property.Name} has no setter."); - // reader.ReadXXX + // reader.ReadXXX + SetField generator.Emit(OpCodes.Ldarg_2); // element generator.Emit(OpCodes.Ldarg_0); // reader generator.Emit(OpCodes.Ldstr, "data"); generator.Emit(OpCodes.Ldarg_1); // namespace URI - - // When writing scalar values we call member methods of XmlReader, while for array values - // we call our own static methods. These two types of methods seem to need different OpCode. - generator.EmitCall( - readMethod.DeclaringType == typeof(XmlReaderExtensions) - ? OpCodes.Call - : OpCodes.Callvirt, - readMethod, - null); - generator.EmitCall(OpCodes.Callvirt, setMethod, null); + EmitCall(generator, readMethod); + EmitCall(generator, setMethod); // Jump to do while generator.Emit(OpCodes.Br, @return); diff --git a/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs b/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs index 0a55adbe3..3a84387b9 100644 --- a/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs +++ b/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs @@ -81,18 +81,6 @@ static WriteDelegateCompiler() typeof(WriteGraphAttributesDelegate)); } - private static void EmitCallWriter([NotNull] ILGenerator generator, [NotNull] MethodInfo writer) - { - // When reading scalar values we call member methods of XmlReader, while for array values - // we call our own static methods. These two types of methods seem to need different OpCode. - generator.EmitCall( - writer.DeclaringType == typeof(XmlWriterExtensions) - ? OpCodes.Call - : OpCodes.Callvirt, - writer, - null); - } - private static void EmitWriteProperty(PropertySerializationInfo info, [NotNull] ILGenerator generator) { var @default = default(Label); @@ -117,7 +105,7 @@ private static void EmitWriteProperty(PropertySerializationInfo info, [NotNull] EmitValue(generator, property, value); generator.Emit(OpCodes.Ldarg_1); - generator.EmitCall(OpCodes.Callvirt, getMethod, null); + EmitCall(generator, getMethod); generator.Emit(OpCodes.Ceq); generator.Emit(OpCodes.Brtrue, @default); } @@ -128,23 +116,23 @@ private static void EmitWriteProperty(PropertySerializationInfo info, [NotNull] generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldstr, "data"); generator.Emit(OpCodes.Ldstr, GraphMLXmlResolver.GraphMLNamespace); - generator.EmitCall(OpCodes.Callvirt, Metadata.WriteStartElementMethod, null); + EmitCall(generator, Metadata.WriteStartElementMethod); // writer.WriteStartAttribute("key"); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldstr, "key"); generator.Emit(OpCodes.Ldstr, info.Name); - generator.EmitCall(OpCodes.Callvirt, Metadata.WriteAttributeStringMethod, null); + EmitCall(generator, Metadata.WriteAttributeStringMethod); // writer.WriteValue(v.xxx); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); - generator.EmitCall(OpCodes.Callvirt, getMethod, null); - EmitCallWriter(generator, writeMethod); + EmitCall(generator, getMethod); + EmitCall(generator, writeMethod); // writer.WriteEndElement() generator.Emit(OpCodes.Ldarg_0); - generator.EmitCall(OpCodes.Callvirt, Metadata.WriteEndElementMethod, null); + EmitCall(generator, Metadata.WriteEndElementMethod); if (defaultValueAttribute != null) { diff --git a/src/QuikGraph.Serialization/Helpers/ILHelpers.cs b/src/QuikGraph.Serialization/Helpers/ILHelpers.cs index 9615d2090..3ae9d72c5 100644 --- a/src/QuikGraph.Serialization/Helpers/ILHelpers.cs +++ b/src/QuikGraph.Serialization/Helpers/ILHelpers.cs @@ -1,4 +1,4 @@ -#if SUPPORTS_GRAPHS_SERIALIZATION +#if SUPPORTS_GRAPHS_SERIALIZATION using System; using System.Diagnostics; using System.Reflection; @@ -44,12 +44,12 @@ public static void EmitValue([NotNull] ILGenerator generator, [NotNull] Property public static void EmitCall([NotNull] ILGenerator generator, [NotNull] MethodInfo method) { - generator.EmitCall( - method.IsVirtual - ? OpCodes.Callvirt - : OpCodes.Call, - method, - null); + // Call the method passing the object on the stack (only virtual if needed) + generator.Emit( + method.IsFinal || !method.IsVirtual + ? OpCodes.Call + : OpCodes.Callvirt, + method); } } } From 131f73aebddb505650da6eb6bf73cbc115055cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 13 Jun 2022 00:14:47 +0200 Subject: [PATCH 31/39] Fix location of some graph interfaces. --- .../Interfaces/{Edges => Graphs}/IEdgeListAndIncidenceGraph.cs | 0 src/QuikGraph/Interfaces/{Edges => Graphs}/IEdgeSet.cs | 0 .../Interfaces/{Vertices => Graphs}/IImplicitVertexSet.cs | 0 .../Interfaces/{Vertices => Graphs}/IMutableVertexSet.cs | 0 src/QuikGraph/Interfaces/{Vertices => Graphs}/IVertexSet.cs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/QuikGraph/Interfaces/{Edges => Graphs}/IEdgeListAndIncidenceGraph.cs (100%) rename src/QuikGraph/Interfaces/{Edges => Graphs}/IEdgeSet.cs (100%) rename src/QuikGraph/Interfaces/{Vertices => Graphs}/IImplicitVertexSet.cs (100%) rename src/QuikGraph/Interfaces/{Vertices => Graphs}/IMutableVertexSet.cs (100%) rename src/QuikGraph/Interfaces/{Vertices => Graphs}/IVertexSet.cs (100%) diff --git a/src/QuikGraph/Interfaces/Edges/IEdgeListAndIncidenceGraph.cs b/src/QuikGraph/Interfaces/Graphs/IEdgeListAndIncidenceGraph.cs similarity index 100% rename from src/QuikGraph/Interfaces/Edges/IEdgeListAndIncidenceGraph.cs rename to src/QuikGraph/Interfaces/Graphs/IEdgeListAndIncidenceGraph.cs diff --git a/src/QuikGraph/Interfaces/Edges/IEdgeSet.cs b/src/QuikGraph/Interfaces/Graphs/IEdgeSet.cs similarity index 100% rename from src/QuikGraph/Interfaces/Edges/IEdgeSet.cs rename to src/QuikGraph/Interfaces/Graphs/IEdgeSet.cs diff --git a/src/QuikGraph/Interfaces/Vertices/IImplicitVertexSet.cs b/src/QuikGraph/Interfaces/Graphs/IImplicitVertexSet.cs similarity index 100% rename from src/QuikGraph/Interfaces/Vertices/IImplicitVertexSet.cs rename to src/QuikGraph/Interfaces/Graphs/IImplicitVertexSet.cs diff --git a/src/QuikGraph/Interfaces/Vertices/IMutableVertexSet.cs b/src/QuikGraph/Interfaces/Graphs/IMutableVertexSet.cs similarity index 100% rename from src/QuikGraph/Interfaces/Vertices/IMutableVertexSet.cs rename to src/QuikGraph/Interfaces/Graphs/IMutableVertexSet.cs diff --git a/src/QuikGraph/Interfaces/Vertices/IVertexSet.cs b/src/QuikGraph/Interfaces/Graphs/IVertexSet.cs similarity index 100% rename from src/QuikGraph/Interfaces/Vertices/IVertexSet.cs rename to src/QuikGraph/Interfaces/Graphs/IVertexSet.cs From 9fb2035609d479e4b445829d79448b0ec53fd280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sat, 25 Jun 2022 23:14:17 +0200 Subject: [PATCH 32/39] Clean GraphML format definitions. --- .../GraphML/graphml-attributes.xsd | 160 +- .../GraphML/graphml-parseinfo.xsd | 444 ++-- .../GraphML/graphml-structure.xsd | 1870 +++++++++-------- .../GraphML/graphml.dtd | 18 +- .../GraphML/graphml.xsd | 494 ++--- src/QuikGraph.Serialization/GraphML/xlink.xsd | 108 +- 6 files changed, 1566 insertions(+), 1528 deletions(-) diff --git a/src/QuikGraph.Serialization/GraphML/graphml-attributes.xsd b/src/QuikGraph.Serialization/GraphML/graphml-attributes.xsd index 361d68208..fdedb5c14 100644 --- a/src/QuikGraph.Serialization/GraphML/graphml-attributes.xsd +++ b/src/QuikGraph.Serialization/GraphML/graphml-attributes.xsd @@ -1,110 +1,104 @@ + - - This document defines the attributes extension of the GraphML language. - It redefines the attribut list of <key> by adding two new - attributes: - - attr.name (gives a name for the data function) and - - attr.type (declares the range of values for the data function). - The data values are defined in #PCDATA children of the corresponding - <data> element. + source="http://graphml.graphdrawing.org/" + xml:lang="en"> + This document defines the attributes extension of the GraphML language. + It redefines the attribute list of <key> by adding two new + attributes: + - attr.name (gives a name for the data function) and + - attr.type (declares the range of values for the data function). + The data values are defined in #PCDATA children of the corresponding + <data> element. + - - - - + - Redefinition of file graphml-structure.xsd. - Extends the attribute group key.extra.attrib (which takes - part in the attribute list of <key>) by adding the - attribute group key.attributes.attrib which is defined below. - - + Redefinition of file graphml-structure.xsd. + Extends the attribute group key.extra.attrib (which takes + part in the attribute list of <key>) by adding the + attribute group key.attributes.attrib which is defined below. + + - - - - + + + + - + - + - - + - Simple type for the attr.name attribute of <key>. - key.name.type is final, that is, it may not be extended - or restricted. - key.name.type is a restriction of xs:NMTOKEN - Allowed values: (no restriction) - - - - - - + Simple type for the attr.name attribute of <key>. + key.name.type is final, that is, it may not be extended + or restricted. + key.name.type is a restriction of xs:NMTOKEN + Allowed values: (no restriction) + + + + - + - - + - Simple type for the attr.type attribute of <key>. - key.type.type is final, that is, it may not be extended - or restricted. - key.type.type is a restriction of xs:NMTOKEN - Allowed values: boolean, int, long, float, double, string. - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - Definition of the attribute group key.attributes.attrib. - This group consists of the two optional attributes - - attr.name (gives the name for the data function) - - attr.type ((declares the range of values for the data function) - - + Definition of the attribute group key.attributes.attrib. + This group consists of the two optional attributes + - attr.name (gives the name for the data function) + - attr.type ((declares the range of values for the data function) + + + + + - - - + \ No newline at end of file diff --git a/src/QuikGraph.Serialization/GraphML/graphml-parseinfo.xsd b/src/QuikGraph.Serialization/GraphML/graphml-parseinfo.xsd index ad90e040c..ac7164498 100644 --- a/src/QuikGraph.Serialization/GraphML/graphml-parseinfo.xsd +++ b/src/QuikGraph.Serialization/GraphML/graphml-parseinfo.xsd @@ -1,295 +1,297 @@ - - + - This document defines the parseinfo extension of the GraphML language. - It redefines the attribut list of <graph> by adding 7 new - attributes: - - parse.nodeids (fixed to 'canonical' meaning that the id attribute - of <node> follows the pattern 'n[number]), - - parse.edgeids (fixed to 'canonical' meaning that the id attribute - of <edge> follows the pattern 'e[number]), - - parse.order (required; one of the values 'nodesfirst', - 'adjacencylist' or 'free'), - - parse.nodes (required; number of nodes in this graph), - - parse.edges (required; number of edges in this graph), - - parse.maxindegree (optional; maximal indegree of a node in this graph), - - parse.maxoutdegree (optional; maximal outdegree of a node in this graph). - and it redefines the attribute list of node by adding 2 new attributes: - - parse.indegree (optional; indegree of this node), - - parse.outdegree (optional; outdegree of this node). - + source="http://graphml.graphdrawing.org/" + xml:lang="en"> + This document defines the parseinfo extension of the GraphML language. + It redefines the attribut list of <graph> by adding 7 new + attributes: + - parse.nodeids (fixed to 'canonical' meaning that the id attribute + of <node> follows the pattern 'n[number]), + - parse.edgeids (fixed to 'canonical' meaning that the id attribute + of <edge> follows the pattern 'e[number]), + - parse.order (required; one of the values 'nodesfirst', + 'adjacencylist' or 'free'), + - parse.nodes (required; number of nodes in this graph), + - parse.edges (required; number of edges in this graph), + - parse.maxindegree (optional; maximal indegree of a node in this graph), + - parse.maxoutdegree (optional; maximal outdegree of a node in this graph). + and it redefines the attribute list of node by adding 2 new attributes: + - parse.indegree (optional; indegree of this node), + - parse.outdegree (optional; outdegree of this node). + - - - - + - Redefinition of file graphml-structure.xsd. - Extends the attribute group graph.extra.attrib (which takes - part in the attribute list of <graph>) by adding the - attribute group graph.parseinfo.attrib which is defined below. - Extends the attribute group node.extra.attrib (which takes - part in the attribute list of <node>) by adding the - attribute group node.parseinfo.attrib which is defined below. - - - - - - - - - - - - - - - + Redefinition of file graphml-structure.xsd. + Extends the attribute group graph.extra.attrib (which takes + part in the attribute list of <graph>) by adding the + attribute group graph.parseinfo.attrib which is defined below. + Extends the attribute group node.extra.attrib (which takes + part in the attribute list of <node>) by adding the + attribute group node.parseinfo.attrib which is defined below. + + + + + + + + + + + + + + - Simple type definitions for the new graph attributes. + source="http://graphml.graphdrawing.org/" + xml:lang="en"> + Simple type definitions for the new graph attributes. - + - - + - Simple type for the parse.order attribute of <graph>. - graph.order.type is final, that is, it may not be extended - or restricted. - graph.order.type is a restriction of xs:NMTOKEN - Allowed values: free, nodesfirst, adjacencylist. - - - - - - - - - - - - - - + + + + + + + + + + + + + + - Simple type for the parse.nodes attribute of <graph>. - graph.nodes.type is final, that is, it may not be extended - or restricted. - graph.nodes.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.nodes attribute of <graph>. + graph.nodes.type is final, that is, it may not be extended + or restricted. + graph.nodes.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.edges attribute of <graph>. - graph.edges.type is final, that is, it may not be extended - or restricted. - graph.edges.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.edges attribute of <graph>. + graph.edges.type is final, that is, it may not be extended + or restricted. + graph.edges.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.maxindegree attribute of <graph>. - graph.maxindegree.type is final, that is, it may not be extended - or restricted. - graph.maxindegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.maxindegree attribute of <graph>. + graph.maxindegree.type is final, that is, it may not be extended + or restricted. + graph.maxindegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.maxoutdegree attribute of <graph>. - graph.maxoutdegree.type is final, that is, it may not be extended - or restricted. - graph.maxoutdegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.maxoutdegree attribute of <graph>. + graph.maxoutdegree.type is final, that is, it may not be extended + or restricted. + graph.maxoutdegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.nodeids attribute of <graph>. - graph.nodeids.type is final, that is, it may not be extended - or restricted. - graph.nodeids.type is a restriction of xs:string - Allowed values: (no restriction). - - + Simple type for the parse.nodeids attribute of <graph>. + graph.nodeids.type is final, that is, it may not be extended + or restricted. + graph.nodeids.type is a restriction of xs:string + Allowed values: (no restriction). + + - - - - - + + + + - + - - + + + - Simple type for the parse.edgeids attribute of <graph>. - graph.edgeids.type is final, that is, it may not be extended - or restricted. - graph.edgeids.type is a restriction of xs:string - Allowed values: (no restriction). - - + Simple type for the parse.edgeids attribute of <graph>. + graph.edgeids.type is final, that is, it may not be extended + or restricted. + graph.edgeids.type is a restriction of xs:string + Allowed values: (no restriction). + + - - - - - + + + + - + - - + + + - Definition of the attribute group graph.parseinfo.attrib. - This group consists of the seven attributes - - parse.nodeids (fixed to 'canonical' meaning that the id attribute - of <node> follows the pattern 'n[number]), - - parse.edgeids (fixed to 'canonical' meaning that the id attribute - of <edge> follows the pattern 'e[number]), - - parse.order (required; one of the values 'nodesfirst', - 'adjacencylist' or 'free'), - - parse.nodes (required; number of nodes in this graph), - - parse.edges (required; number of edges in this graph), - - parse.maxindegree (optional; maximal indegree of a node in this graph), - - parse.maxoutdegree (optional; maximal outdegree of a node in this graph) - - - - - - - - - - - - + Definition of the attribute group graph.parseinfo.attrib. + This group consists of the seven attributes + - parse.nodeids (fixed to 'canonical' meaning that the id attribute + of <node> follows the pattern 'n[number]), + - parse.edgeids (fixed to 'canonical' meaning that the id attribute + of <edge> follows the pattern 'e[number]), + - parse.order (required; one of the values 'nodesfirst', + 'adjacencylist' or 'free'), + - parse.nodes (required; number of nodes in this graph), + - parse.edges (required; number of edges in this graph), + - parse.maxindegree (optional; maximal indegree of a node in this graph), + - parse.maxoutdegree (optional; maximal outdegree of a node in this graph) + + + + + + + + + + + - Simple type definitions for the new node attributes. + source="http://graphml.graphdrawing.org/" + xml:lang="en"> + Simple type definitions for the new node attributes. - + - - + - Simple type for the parse.indegree attribute of <node>. - node.indegree.type is final, that is, it may not be extended - or restricted. - node.indegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.indegree attribute of <node>. + node.indegree.type is final, that is, it may not be extended + or restricted. + node.indegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.outdegree attribute of <node>. - node.outdegree.type is final, that is, it may not be extended - or restricted. - node.outdegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.outdegree attribute of <node>. + node.outdegree.type is final, that is, it may not be extended + or restricted. + node.outdegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Definition of the attribute group node.parseinfo.attrib. - This group consists of two attributes - - parse.indegree (optional; indegree of this node), - - parse.outdegree (optional; outdegree of this node). - - + Definition of the attribute group node.parseinfo.attrib. + This group consists of two attributes + - parse.indegree (optional; indegree of this node), + - parse.outdegree (optional; outdegree of this node). + + - - - + + + + \ No newline at end of file diff --git a/src/QuikGraph.Serialization/GraphML/graphml-structure.xsd b/src/QuikGraph.Serialization/GraphML/graphml-structure.xsd index adca0ac57..0f1515ff8 100644 --- a/src/QuikGraph.Serialization/GraphML/graphml-structure.xsd +++ b/src/QuikGraph.Serialization/GraphML/graphml-structure.xsd @@ -1,1134 +1,1176 @@ + - - - The schema corresponding to this document defines the structural - layer of the Graph Markup Language (GraphML). - Although a DTD is provided, this schema is, together with its extensions - http://graphml.graphdrawing.org/xmlns/1.1/graphml-attributes.xsd - and - http://graphml.graphdrawing.org/xmlns/1.1/graphml-parseinfo.xsd, - the only normative reference. + + The schema corresponding to this document defines the structural + layer of the Graph Markup Language (GraphML). + Although a DTD is provided, this schema is, together with its extensions + http://graphml.graphdrawing.org/xmlns/1.1/graphml-attributes.xsd + and + http://graphml.graphdrawing.org/xmlns/1.1/graphml-parseinfo.xsd, + the only normative reference. - - - + + - Get access to the xlink attribute groups for the attributes - xlink:href and xlink:type of locator.type. - - - + Get access to the xlink attribute groups for the attributes + xlink:href and xlink:type of locator.type. + + + - - The attribute groups <element_name>.extra.attrib may be used + + The attribute groups <element_name>.extra.attrib may be used for adding user defined attributes to the elements - <element_name>. + <element_name>. The attribute group common.extra.attrib may be used for adding user defined attributes to all elements. + - - - - - - - - - - - - - - - - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + + + + + + + + + + - + Complex type definitions for the GraphML structural layer elements: - <data>, <default>, <key>, <graphml>, <graph>, - <node>, <port>, - <edge>, <hyperedge>, <endpoint> and <locator>. + <data>, <default>, <key>, <graphml>, <graph>, + <node>, <port>, + <edge>, <hyperedge>, <endpoint> and <locator>. The names of the complex types are constructed corresponding to the pattern element_name.type. (The only remaining GraphML structural layer element - <desc> is of simple type xs:string.) + <desc> is of simple type xs:string.) - - - - + + - Extension mechanism for the content of <data> and <default>. - The complex type data-extension.type is empty per default. - Users may redefine this type in order to add content to - the complex types data.type and default.type which are - extensions of data-extension.type. - - - + Extension mechanism for the content of <data> and <default>. + The complex type data-extension.type is empty per default. + Users may redefine this type in order to add content to + the complex types data.type and default.type which are + extensions of data-extension.type. + + + + - - - + - Complex type for the <data> element. - data.type is mixed, that is, <data> may contain #PCDATA. - Content type: extension of data-extension.type which is empty - per default. - - - - - - - + + + + + + + refers to the id attribute of a <key>. - - - - - - refers to the id attribute of a <key>. + + + + + + - - - - - - + + + + + identifies this <data>. - - - - - - identifies this <data>. + + + + + + - user defined extra attributes for <data> elements - - - - - - + xml:lang="en">user defined extra attributes for <data> elements. + + + + + + - - - + + + - Complex type for the <default> element. - default.type is mixed, that is, data may contain #PCDATA. - Content type: extension of data-extension.type which is empty - per default. - - - - - - - + + + + + + + - user defined extra attributes for <default> elements - - - - - - + xml:lang="en">user defined extra attributes for <default> elements. + + + + + + + - - - - Simple type for the for attribute of <key>. - key.for.type is a restriction of xs:NMTOKEN - Allowed values: all, graphml, graph, node, edge, hyperedge, port and endpoint. - - - - - - - - - - - - - - - - - - + - Complex type for the <key> element. - - - - - - - - - identifies this <key>. - - - - - - - - - - - - - describes the domain of definition for - the corresponding graph attribute. - - - - - - - user defined extra attributes for <key> elements. - - - - + Simple type for the for attribute of <key>. + key.for.type is a restriction of xs:NMTOKEN + Allowed values: all, graphml, graph, node, edge, hyperedge, port and endpoint. + + + + + + + + + + + + - - - + + + + + - Complex type for the <graphml> element. - - - - - + Complex type for the <key> element. + + + - - - - + + - - - - - user defined extra attributes for <graphml> elements. - - - - + + + identifies this <key>. + + + + + + + + + + - - - - Simple type for the edgedefault attribute of <graph>. - graph.edgedefault.type is a restriction of xs:NMTOKEN - Allowed values: directed, undirected. - - - - - - - + + + + Describes the domain of definition for + the corresponding graph attribute. + + + + + + + + user defined extra attributes for <key> elements. + + + + - - - + + + - Complex type for the <graph> element. - - - - - + Complex type for the <graphml> element. + + + + + + + - - - - - - - - - - user defined extra attributes for <graph> elements. - - - - - - - identifies this graph . - - - - - - - describes whether edges of this graph are considered - as directed or undirected per default (unless - specified by the attribute directed of <edge>). - - - - + + + + + user defined extra attributes for <graphml> elements. + + + + - - - + + + - Complex type for the <node> element. - - - - - - - - - - - - - - - - - - - user defined extra attributes for <node elements. - - - - - - - identifies this node. - - - - - + Simple type for the edgedefault attribute of <graph>. + graph.edgedefault.type is a restriction of xs:NMTOKEN + Allowed values: directed, undirected. + + + + + + - - - - Complex type for the <port> element. - - - - - - - - - - - - - user defined extra attributes for <port> elements. - - - - - - - identifies this port, within the node it is contained in. - - - - - + + - - - + - Complex type for the <edge> element. - - - - - - - - - - - user defined extra attributes for <edge> elements. - - - - - - - identifies this edge . - - - - - - - overwrites the edgedefault attribute of <graph> . - - - - - - - points to the id attribute of the source <node>. - - - - - - - points to the id attribute of the target <node>. - - - - - - - points to the name attribute of the source <port>. - - - - - - - points to the name attribute of the target <port>. - - - - + Complex type for the <graph> element. + + + + + + + + + + + + + + + + - - - - Complex type for the <hyperedge> element. - - - - - - - - - - - - - - user defined extra attributes for <hyperedge> elements. - - - - - - - identifies this <hyperedge> . - - - - - - - - - - Simple type for the type attribute of <endpoint>. - endpoint.type.type is a restriction of xs:NMTOKEN - Allowed values: in, out, undir. - - - - - - - - - - - - - Complex type for the <endpoint> element. - - - - - - - - - user defined extra attributes for <endpoint> elements. - - - - - - - identifies this <endpoint> . - - - - - - - points to the name of the port, to which this endpoint is - connected . - - - - - - - points to the id of the node, to which this endpoint is connected. - - - - - - - defines the direction on this endpoint (undirected per default). - - - - + + + + user defined extra attributes for <graph> elements. + + + + + + + + identifies this graph. + + + + + + + + describes whether edges of this graph are considered + as directed or undirected per default (unless + specified by the attribute directed of <edge>). + + + + - - - + + + - Complex type for the <locator> element. - Content type: (empty) - - - - - - user defined extra attributes for <locator> elements. - - - - - - - points to the resource of this locator. - - - - - - - - type of the hyperlink (fixed as simple). - - - - + Complex type for the <node> element. + + - + + + + + + + + + + + + + - - - + + + user defined extra attributes for <node> elements. + + + + + + + - Description: Provides human-readable descriptions for the GraphML - element containing this <desc> as its first child. - Occurence: <key>, <graphml>, <graph>, - <node>, <port>, <edge>, <hyperedge>, and - <endpoint>. + identifies this node. + + + + + + + + + + + Complex type for the <port> element. - + + + + + + + - - - + + - Description: Graphs and nodes are declared by the elements - <graph> and <node>, respectively. The optional - <locator>-child of these elements point to - their definition. (If there is no <locator>-child - the graphs/nodes are defined by their content). - Occurence: <graph>, and <node>. - - - + user defined extra attributes for <port> elements. + + + + + + + + identifies this port, within the node it is contained in. + + + + + - + - - Description: In GraphML there may be data-functions attached - to graphs, nodes, ports, edges, hyperedges and - endpoint and to the whole collection of - graphs described by the content of <graphml>. - These functions are declared by <key> elements - (children of <graphml>) and defined by <data> - elements. - Occurence: <graphml>, <graph>, <node>, <port>, - <edge>, <hyperedge>, and <endpoint>. + Complex type for the <edge> element. - - - + + + + + + + + - Ensures: uniqueness of the key attributes of <data> children - of this <data> element. - - - - - - + xml:lang="en"> + user defined extra attributes for <edge> elements. + + + + + + + + identifies this edge. + + + + + + + + overwrites the edgedefault attribute of <graph>. + + + + + + + + points to the id attribute of the source <node>. + + + + + + + + points to the id attribute of the target <node>. + + + + + + + + points to the name attribute of the source <port>. + + + + + + + + points to the name attribute of the target <port>. + + + - + + - - - Description: In GraphML there may be data-functions attached - to graphs, nodes, ports, edges, hyperedges and - endpoint and to the whole collection of - graphs described by the content of <graphml>. - These functions are declared by <key> elements - (children of <graphml>) and defined by <data> - elements. - Occurence: <graphml>. + + Complex type for the <hyperedge> element. - - - - + + + + + + + + + + + - Description: In GraphML there may be data-functions attached - to graphs, nodes, ports, edges, hyperedges and - endpoint and to the whole collection of - graphs described by the content of <graphml>. - These functions are declared by <key> elements - (children of <graphml>) and defined by <data> - elements. - The (optional) <default> child of <key> gives - the default value for the corresponding function. - Occurence: <key>. - - - - - - - + + + + + + - Description: <graphml> is the root element of each GraphML - document. - Occurence: root. - - + identifies this <hyperedge>. + + + + + + + - - - Ensures: uniqueness of the key attributes of <data> children - of this <graphml> element. + + Simple type for the type attribute of <endpoint>. + endpoint.type.type is a restriction of xs:NMTOKEN + Allowed values: in, out, undir. - - - - - + + + + + + + + + + - - Ensures: existence and uniqueness of the id attributes of - each <key> element in this document. + + Complex type for the <endpoint> element. - - - + + + - - - + + - Ensures: uniqueness of the id attributes of - each <graph> element in this document. - - - - - - - - - + + + + + + + identifies this <endpoint>. + + + + + + + - Ensures: for the key attribute of each <data> in this document, - the existence of an id attribute of - <key> which matches the value of it. + points to the name of the port, to which this endpoint is connected. + + + + + + + + points to the id of the node, to which this endpoint is connected. + + + + + + + + defines the direction on this endpoint (undirected per default). + + + + + + + + + + + Complex type for the <locator> element. + Content type: (empty) - - - - + + + + user defined extra attributes for <locator> elements. + + + + + + + + points to the resource of this locator. + + + + + + + + + type of the hyperlink (fixed as simple). + + + + + - + - - Description: Describes one graph in this document. - Occurence: <graphml>, <node>, <edge>, <hyperedge>. + + Description: Provides human-readable descriptions for the GraphML + element containing this <desc> as its first child. + Occurrence: <key>, <graphml>, <graph>, + <node>, <port>, <edge>, <hyperedge>, and + <endpoint>. - + + + - - Ensures: uniqueness of the key attributes of <data> children - of this <graph> element. + + Description: Graphs and nodes are declared by the elements + <graph> and <node>, respectively. The optional + <locator>-child of these elements point to + their definition. (If there is no <locator>-child + the graphs/nodes are defined by their content). + Occurrence: <graph>, and <node>. - - - - + + + - - - Ensures: existence and uniqueness of the id attributes of - each <node> element in this graph. + + Description: In GraphML there may be data-functions attached + to graphs, nodes, ports, edges, hyperedges and + endpoint and to the whole collection of + graphs described by the content of <graphml>. + These functions are declared by <key> elements + (children of <graphml>) and defined by <data> + elements. + Occurrence: <graphml>, <graph>, <node>, <port>, + <edge>, <hyperedge>, and <endpoint>. - - - - - - + + - Ensures: uniqueness of the id attributes of - each <edge> element in this graph. - - - - - + Ensures: uniqueness of the key attributes of <data> children + of this <data> element. + + + + + + + + + + - - - Ensures: uniqueness of the id attributes of - each <hyperedge> element in this graph. + + Description: In GraphML there may be data-functions attached + to graphs, nodes, ports, edges, hyperedges and + endpoint and to the whole collection of + graphs described by the content of <graphml>. + These functions are declared by <key> elements + (children of <graphml>) and defined by <data> + elements. + Occurrence: <graphml>. - - - - + + + + - - Ensures: uniqueness of the id attributes of - each <endpoint> element in this graph. + + Description: In GraphML there may be data-functions attached + to graphs, nodes, ports, edges, hyperedges and + endpoint and to the whole collection of + graphs described by the content of <graphml>. + These functions are declared by <key> elements + (children of <graphml>) and defined by <data> + elements. + The (optional) <default> child of <key> gives + the default value for the corresponding function. + Occurrence: <key>. - - - - + + + + - - Ensures: for the source attribute of each <edge> in this graph, - the existence of an id attribute of - <node> which matches the value of it. + + Description: <graphml> is the root element of each GraphML + document. + Occurrence: root. - - - - - - + + - Ensures: for the target attribute of each <edge> in this graph, - the existence of an id attribute of - <node> which matches the value of it. - - - - - - - - - + + + + + + + + + - Ensures: for the node attribute of each <endpoint> in this graph, - the existence of an id attribute of - <node> which matches the value of it. - - - - - + Ensures: existence and uniqueness of the id attributes of + each <key> element in this document. + + + + + + + + + + Ensures: uniqueness of the id attributes of + each <graph> element in this document. + + + + + + + + + + Ensures: for the key attribute of each <data> in this document, + the existence of an id attribute of + <key> which matches the value of it. + + + + + - + + - - - Description: Describes one node in the <graph> - containing this <node>. - Occurence: <graph>. + + Description: Describes one graph in this document. + Occurrence: <graphml>, <node>, <edge>, <hyperedge>. - - - + + - Ensures: existence and uniqueness of the name attributes of - each <port> element within this <node>. - - - - - - - - - + + + + + + + + + - Ensures: uniqueness of the key attributes of <data> children - of this <node> element. - - - - - - + Ensures: existence and uniqueness of the id attributes of + each <node> element in this graph. + + + + + + + + + + Ensures: uniqueness of the id attributes of + each <edge> element in this graph. + + + + + + + + + + Ensures: uniqueness of the id attributes of + each <hyperedge> element in this graph. + + + + + + + + + + Ensures: uniqueness of the id attributes of + each <endpoint> element in this graph. + + + + + + + + + + Ensures: for the source attribute of each <edge> in this graph, + the existence of an id attribute of + <node> which matches the value of it. + + + + + + + + + + Ensures: for the target attribute of each <edge> in this graph, + the existence of an id attribute of + <node> which matches the value of it. + + + + + + + + + + Ensures: for the node attribute of each <endpoint> in this graph, + the existence of an id attribute of + <node> which matches the value of it. + + + + + - + + - - - Description: Nodes may be structured by ports; thus edges - are not only attached to a node but to a certain - port in this node. - Occurence: <node>, <port>. + + Description: Describes one node in the <graph> + containing this <node>. + Occurrence: <graph>. - - - + + - Ensures: uniqueness of the key attributes of <data> children - of this <port> element. - - - - - - + Ensures: existence and uniqueness of the name attributes of + each <port> element within this <node>. + + + + + + + + + + Ensures: uniqueness of the key attributes of <data> children + of this <node> element. + + + + + + - + + - - - Description: Describes an edge in the <graph> which contains this - <edge>. - Occurence: <graph>. + + Description: Nodes may be structured by ports; thus edges + are not only attached to a node but to a certain + port in this node. + Occurrence: <node>, <port>. - - - + + - Ensures: uniqueness of the key attributes of <data> children - of this <edge> element. + Ensures: uniqueness of the key attributes of <data> children + of this <port> element. + + + + + + + + + + + + + + Description: Describes an edge in the <graph> which contains this + <edge>. + Occurrence: <graph>. - - - - - + + + + Ensures: uniqueness of the key attributes of <data> children + of this <edge> element. + + + + + + + + + - - - Description: While edges describe relations between two nodes, - a hyperedge describes a relation between an arbitrary - number of nodes. - Occurence: <graph>. + + Description: While edges describe relations between two nodes, + a hyperedge describes a relation between an arbitrary + number of nodes. + Occurrence: <graph>. - - - + + - Ensures: uniqueness of the key attributes of <data> children - of this <hyperedge> element. - - - - - - + Ensures: uniqueness of the key attributes of <data> children + of this <hyperedge> element. + + + + + + - + + - - - Description: The list of <endpoints> within a hyperedge - points to the nodes contained in this hyperedge. - Occurence: <hyperedge>. + + Description: The list of <endpoints> within a hyperedge + points to the nodes contained in this hyperedge. + Occurrence: <hyperedge>. - + + \ No newline at end of file diff --git a/src/QuikGraph.Serialization/GraphML/graphml.dtd b/src/QuikGraph.Serialization/GraphML/graphml.dtd index d378688eb..85f6c3811 100644 --- a/src/QuikGraph.Serialization/GraphML/graphml.dtd +++ b/src/QuikGraph.Serialization/GraphML/graphml.dtd @@ -3,18 +3,17 @@ + ====================================================================== --> - + - @@ -25,6 +24,7 @@ xlink:type (simple) #FIXED "simple" > + @@ -32,13 +32,15 @@ +> + - + + + +> + - - + - This document defines the GraphML language including GraphML attributes and GraphML parseinfo. + source="http://graphml.graphdrawing.org/" + xml:lang="en"> + This document defines the GraphML language including GraphML attributes and GraphML parseinfo. + - - - - - - - - - - - - - + + + + + - - - - + + + + + - + + + + + - - + + - - + - Simple type for the attr.name attribute of <key>. - key.name.type is final, that is, it may not be extended - or restricted. - key.name.type is a restriction of xs:NMTOKEN - Allowed values: (no restriction) - - - - + Simple type for the attr.name attribute of <key>. + key.name.type is final, that is, it may not be extended + or restricted. + key.name.type is a restriction of xs:NMTOKEN + Allowed values: (no restriction) + + - + + + - - - - + - Simple type for the attr.type attribute of <key>. - key.type.type is final, that is, it may not be extended - or restricted. - key.type.type is a restriction of xs:NMTOKEN - Allowed values: boolean, int, long, float, double, string. - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - Definition of the attribute group key.attributes.attrib. - This group consists of the two optional attributes - - attr.name (gives the name for the data function) - - attr.type ((declares the range of values for the data function) - - + Definition of the attribute group key.attributes.attrib. + This group consists of the two optional attributes + - attr.name (gives the name for the data function) + - attr.type ((declares the range of values for the data function) + + - - - + + - + + - Simple type definitions for the new graph attributes. + Simple type definitions for the new graph attributes. - + - - + - Simple type for the parse.order attribute of <graph>. - graph.order.type is final, that is, it may not be extended - or restricted. - graph.order.type is a restriction of xs:NMTOKEN - Allowed values: free, nodesfirst, adjacencylist. - - - - - - - - - - - - - - + + + + + + + + + + + + + + - Simple type for the parse.nodes attribute of <graph>. - graph.nodes.type is final, that is, it may not be extended - or restricted. - graph.nodes.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.nodes attribute of <graph>. + graph.nodes.type is final, that is, it may not be extended + or restricted. + graph.nodes.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.edges attribute of <graph>. - graph.edges.type is final, that is, it may not be extended - or restricted. - graph.edges.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.edges attribute of <graph>. + graph.edges.type is final, that is, it may not be extended + or restricted. + graph.edges.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.maxindegree attribute of <graph>. - graph.maxindegree.type is final, that is, it may not be extended - or restricted. - graph.maxindegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.maxindegree attribute of <graph>. + graph.maxindegree.type is final, that is, it may not be extended + or restricted. + graph.maxindegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.maxoutdegree attribute of <graph>. - graph.maxoutdegree.type is final, that is, it may not be extended - or restricted. - graph.maxoutdegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.maxoutdegree attribute of <graph>. + graph.maxoutdegree.type is final, that is, it may not be extended + or restricted. + graph.maxoutdegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.nodeids attribute of <graph>. - graph.nodeids.type is final, that is, it may not be extended - or restricted. - graph.nodeids.type is a restriction of xs:string - Allowed values: (no restriction). - - + Simple type for the parse.nodeids attribute of <graph>. + graph.nodeids.type is final, that is, it may not be extended + or restricted. + graph.nodeids.type is a restriction of xs:string + Allowed values: (no restriction). + + - - - - - + + + + - + - - + + + - Simple type for the parse.edgeids attribute of <graph>. - graph.edgeids.type is final, that is, it may not be extended - or restricted. - graph.edgeids.type is a restriction of xs:string - Allowed values: (no restriction). - - + Simple type for the parse.edgeids attribute of <graph>. + graph.edgeids.type is final, that is, it may not be extended + or restricted. + graph.edgeids.type is a restriction of xs:string + Allowed values: (no restriction). + + - - - - - + + + + - + - - + + + - Definition of the attribute group graph.parseinfo.attrib. - This group consists of the seven attributes - - parse.nodeids (fixed to 'canonical' meaning that the id attribute - of <node> follows the pattern 'n[number]), - - parse.edgeids (fixed to 'canonical' meaning that the id attribute - of <edge> follows the pattern 'e[number]), - - parse.order (required; one of the values 'nodesfirst', - 'adjacencylist' or 'free'), - - parse.nodes (required; number of nodes in this graph), - - parse.edges (required; number of edges in this graph), - - parse.maxindegree (optional; maximal indegree of a node in this graph), - - parse.maxoutdegree (optional; maximal outdegree of a node in this graph) - - - - - - - - - - - - + Definition of the attribute group graph.parseinfo.attrib. + This group consists of the seven attributes + - parse.nodeids (fixed to 'canonical' meaning that the id attribute + of <node> follows the pattern 'n[number]), + - parse.edgeids (fixed to 'canonical' meaning that the id attribute + of <edge> follows the pattern 'e[number]), + - parse.order (required; one of the values 'nodesfirst', + 'adjacencylist' or 'free'), + - parse.nodes (required; number of nodes in this graph), + - parse.edges (required; number of edges in this graph), + - parse.maxindegree (optional; maximal indegree of a node in this graph), + - parse.maxoutdegree (optional; maximal outdegree of a node in this graph) + + + + + + + + + + + - Simple type definitions for the new node attributes. + source="http://graphml.graphdrawing.org/" + xml:lang="en"> + Simple type definitions for the new node attributes. - + - - + - Simple type for the parse.indegree attribute of <node>. - node.indegree.type is final, that is, it may not be extended - or restricted. - node.indegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.indegree attribute of <node>. + node.indegree.type is final, that is, it may not be extended + or restricted. + node.indegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Simple type for the parse.outdegree attribute of <node>. - node.outdegree.type is final, that is, it may not be extended - or restricted. - node.outdegree.type is a restriction of xs:nonNegativeInteger - Allowed values: (no restriction). - - + Simple type for the parse.outdegree attribute of <node>. + node.outdegree.type is final, that is, it may not be extended + or restricted. + node.outdegree.type is a restriction of xs:nonNegativeInteger + Allowed values: (no restriction). + + - - + - + - - + + + - Definition of the attribute group node.parseinfo.attrib. - This group consists of two attributes - - parse.indegree (optional; indegree of this node), - - parse.outdegree (optional; outdegree of this node). - - + Definition of the attribute group node.parseinfo.attrib. + This group consists of two attributes + - parse.indegree (optional; indegree of this node), + - parse.outdegree (optional; outdegree of this node). + + - - - + + + + \ No newline at end of file diff --git a/src/QuikGraph.Serialization/GraphML/xlink.xsd b/src/QuikGraph.Serialization/GraphML/xlink.xsd index 9dd85b206..734069803 100644 --- a/src/QuikGraph.Serialization/GraphML/xlink.xsd +++ b/src/QuikGraph.Serialization/GraphML/xlink.xsd @@ -1,59 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 23c9ee02f5b706954aaada49a23e9fcd49e57d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 26 Jun 2022 12:34:38 +0200 Subject: [PATCH 33/39] Fix GraphML deserialization where some data were skipped. --- .../GraphML/GraphMLDeserializer.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs b/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs index 61bb7e5ed..cf3c1919b 100644 --- a/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs +++ b/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs @@ -394,9 +394,9 @@ private void ReadEdge([NotNull] IDictionary vertices) // Read data while (subReader.Read()) { - if (_reader.NodeType == XmlNodeType.Element - && _reader.Name == DataTag - && _reader.NamespaceURI == _graphMLNamespace) + while (subReader.NodeType == XmlNodeType.Element + && subReader.Name == DataTag + && subReader.NamespaceURI == _graphMLNamespace) { ReadDelegateCompiler.EdgeAttributesReader(subReader, _graphMLNamespace, edge); } @@ -423,12 +423,13 @@ private void ReadVertex([NotNull] IDictionary vertices) TVertex vertex = _vertexFactory(id); // Apply defaults ReadDelegateCompiler.SetVertexDefault(vertex); + // Read data while (subReader.Read()) { - if (_reader.NodeType == XmlNodeType.Element - && _reader.Name == DataTag - && _reader.NamespaceURI == _graphMLNamespace) + while (subReader.NodeType == XmlNodeType.Element + && subReader.Name == DataTag + && subReader.NamespaceURI == _graphMLNamespace) { ReadDelegateCompiler.VertexAttributesReader(subReader, _graphMLNamespace, vertex); } From 74c396b182fcda9a6e8933ce9a5c49dd43a05895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 26 Jun 2022 12:35:27 +0200 Subject: [PATCH 34/39] Better handle null string value through GraphML serialization. --- .../GraphML/GraphMLDeserializer.cs | 70 +++++++++++-------- .../GraphML/GraphMLSerializer.cs | 40 ++++++++--- .../GraphML/XmlReaderExtensions.cs | 26 +++++++ 3 files changed, 98 insertions(+), 38 deletions(-) diff --git a/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs b/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs index cf3c1919b..9d0103e81 100644 --- a/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs +++ b/src/QuikGraph.Serialization/GraphML/GraphMLDeserializer.cs @@ -168,16 +168,17 @@ private static Delegate CreateReadDelegate( var method = new DynamicMethod( $"{DynamicMethodPrefix}Read{elementType.Name}", typeof(void), - // reader, namespaceUri new[] { typeof(XmlReader), typeof(string), elementType }, elementType.Module); ILGenerator generator = method.GetILGenerator(); + // Ldarg_0 = reader + // Ldarg_1 = namespace URI + // Ldarg_2 = element + generator.DeclareLocal(typeof(string)); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldstr, "key"); - EmitCall(generator, Metadata.GetAttributeMethod); + GetXmlAttribute("key"); generator.Emit(OpCodes.Stloc_0); // We need to create the switch for each property @@ -210,7 +211,7 @@ private static Delegate CreateReadDelegate( if (setMethod is null) throw new InvalidOperationException($"Property {property.DeclaringType}.{property.Name} has no setter."); - // reader.ReadXXX + SetField + // element.xxx = reader.ReadXXX generator.Emit(OpCodes.Ldarg_2); // element generator.Emit(OpCodes.Ldarg_0); // reader generator.Emit(OpCodes.Ldstr, "data"); @@ -233,6 +234,17 @@ private static Delegate CreateReadDelegate( // Let's bake the method return method.CreateDelegate(delegateType); + + #region Local function + + void GetXmlAttribute(string attributeName) + { + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldstr, attributeName); + EmitCall(generator, Metadata.GetAttributeMethod); + } + + #endregion } } @@ -368,12 +380,12 @@ private void ReadElements() } } - private void ReadEdge([NotNull] IDictionary vertices) + private void ReadVertex([NotNull] IDictionary vertices) { Debug.Assert(vertices != null); Debug.Assert( _reader.NodeType == XmlNodeType.Element - && _reader.Name == EdgeTag + && _reader.Name == NodeTag && _reader.NamespaceURI == _graphMLNamespace); // Get subtree @@ -381,15 +393,10 @@ private void ReadEdge([NotNull] IDictionary vertices) { // Read id string id = ReadAttributeValue(_reader, IdAttribute); - string sourceId = ReadAttributeValue(_reader, SourceAttribute); - if (!vertices.TryGetValue(sourceId, out TVertex source)) - throw new ArgumentException($"Could not find vertex {sourceId}."); - string targetId = ReadAttributeValue(_reader, TargetAttribute); - if (!vertices.TryGetValue(targetId, out TVertex target)) - throw new ArgumentException($"Could not find vertex {targetId}."); - - TEdge edge = _edgeFactory(source, target, id); - ReadDelegateCompiler.SetEdgeDefault(edge); + // Create new vertex + TVertex vertex = _vertexFactory(id); + // Apply defaults + ReadDelegateCompiler.SetVertexDefault(vertex); // Read data while (subReader.Read()) @@ -398,20 +405,22 @@ private void ReadEdge([NotNull] IDictionary vertices) && subReader.Name == DataTag && subReader.NamespaceURI == _graphMLNamespace) { - ReadDelegateCompiler.EdgeAttributesReader(subReader, _graphMLNamespace, edge); + ReadDelegateCompiler.VertexAttributesReader(subReader, _graphMLNamespace, vertex); } } - _graph.AddEdge(edge); + // Add to graph + _graph.AddVertex(vertex); + vertices.Add(id, vertex); } } - private void ReadVertex([NotNull] IDictionary vertices) + private void ReadEdge([NotNull] IDictionary vertices) { Debug.Assert(vertices != null); Debug.Assert( _reader.NodeType == XmlNodeType.Element - && _reader.Name == NodeTag + && _reader.Name == EdgeTag && _reader.NamespaceURI == _graphMLNamespace); // Get subtree @@ -419,10 +428,15 @@ private void ReadVertex([NotNull] IDictionary vertices) { // Read id string id = ReadAttributeValue(_reader, IdAttribute); - // Create new vertex - TVertex vertex = _vertexFactory(id); - // Apply defaults - ReadDelegateCompiler.SetVertexDefault(vertex); + string sourceId = ReadAttributeValue(_reader, SourceAttribute); + if (!vertices.TryGetValue(sourceId, out TVertex source)) + throw new ArgumentException($"Could not find vertex {sourceId}."); + string targetId = ReadAttributeValue(_reader, TargetAttribute); + if (!vertices.TryGetValue(targetId, out TVertex target)) + throw new ArgumentException($"Could not find vertex {targetId}."); + + TEdge edge = _edgeFactory(source, target, id); + ReadDelegateCompiler.SetEdgeDefault(edge); // Read data while (subReader.Read()) @@ -431,13 +445,11 @@ private void ReadVertex([NotNull] IDictionary vertices) && subReader.Name == DataTag && subReader.NamespaceURI == _graphMLNamespace) { - ReadDelegateCompiler.VertexAttributesReader(subReader, _graphMLNamespace, vertex); + ReadDelegateCompiler.EdgeAttributesReader(subReader, _graphMLNamespace, edge); } } - // Add to graph - _graph.AddVertex(vertex); - vertices.Add(id, vertex); + _graph.AddEdge(edge); } } @@ -495,7 +507,7 @@ private static Dictionary InitializeReadMethods() [typeof(long)] = readerType.GetMethod(nameof(XmlReader.ReadElementContentAsLong), new[] { typeof(string), typeof(string) }), [typeof(float)] = readerType.GetMethod(nameof(XmlReader.ReadElementContentAsFloat), new[] { typeof(string), typeof(string) }), [typeof(double)] = readerType.GetMethod(nameof(XmlReader.ReadElementContentAsDouble), new[] { typeof(string), typeof(string) }), - [typeof(string)] = readerType.GetMethod(nameof(XmlReader.ReadElementContentAsString), new[] { typeof(string), typeof(string) }), + [typeof(string)] = readerExtensionsType.GetMethod(nameof(XmlReaderExtensions.ReadElementAsNullableString)), // Extensions [typeof(bool[])] = readerExtensionsType.GetMethod(nameof(XmlReaderExtensions.ReadElementContentAsBooleanArray)), diff --git a/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs b/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs index 3a84387b9..6158388d9 100644 --- a/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs +++ b/src/QuikGraph.Serialization/GraphML/GraphMLSerializer.cs @@ -92,8 +92,12 @@ private static void EmitWriteProperty(PropertySerializationInfo info, [NotNull] if (!Metadata.TryGetWriteValueMethod(property.PropertyType, out MethodInfo writeMethod)) throw new NotSupportedException($"Property {property.DeclaringType}.{property.Name} type is not supported."); - var defaultValueAttribute = - Attribute.GetCustomAttribute(property, typeof(DefaultValueAttribute)) as DefaultValueAttribute; + // Ldarg_0 = writer + // Ldarg_1 = element + + var defaultValueAttribute = Attribute.GetCustomAttribute( + property, + typeof(DefaultValueAttribute)) as DefaultValueAttribute; if (defaultValueAttribute != null) { @default = generator.DefineLabel(); @@ -119,15 +123,11 @@ private static void EmitWriteProperty(PropertySerializationInfo info, [NotNull] EmitCall(generator, Metadata.WriteStartElementMethod); // writer.WriteStartAttribute("key"); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldstr, "key"); - generator.Emit(OpCodes.Ldstr, info.Name); - EmitCall(generator, Metadata.WriteAttributeStringMethod); + WriteXmlAttribute("key", info.Name); - // writer.WriteValue(v.xxx); + // writer.WriteValue(element.xxx); generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - EmitCall(generator, getMethod); + GetFieldValue(); EmitCall(generator, writeMethod); // writer.WriteEndElement() @@ -138,6 +138,28 @@ private static void EmitWriteProperty(PropertySerializationInfo info, [NotNull] { generator.MarkLabel(@default); } + + #region Local functions + + void GetFieldValue() + { + generator.Emit(OpCodes.Ldarg_1); + EmitCall(generator, getMethod); + } + + void WriteXmlAttribute(string attributeName, string attributeValue) + { + Debug.Assert(generator != null); + Debug.Assert(attributeName != null); + Debug.Assert(attributeValue != null); + + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldstr, attributeName); + generator.Emit(OpCodes.Ldstr, attributeValue); + EmitCall(generator, Metadata.WriteAttributeStringMethod); + } + + #endregion } [NotNull] diff --git a/src/QuikGraph.Serialization/GraphML/XmlReaderExtensions.cs b/src/QuikGraph.Serialization/GraphML/XmlReaderExtensions.cs index 39d7111e6..8114662bc 100644 --- a/src/QuikGraph.Serialization/GraphML/XmlReaderExtensions.cs +++ b/src/QuikGraph.Serialization/GraphML/XmlReaderExtensions.cs @@ -9,6 +9,32 @@ namespace QuikGraph.Serialization /// public static class XmlReaderExtensions { + /// + /// Reads a named element as a string. + /// + /// XML reader. + /// Node name. + /// XML namespace. + /// Boolean array. + /// is . + /// is . + /// is empty. + [Pure] + [CanBeNull] + public static string ReadElementAsNullableString( + [NotNull] XmlReader xmlReader, + [NotNull] string localName, + [NotNull] string namespaceURI) + { + bool isNull = xmlReader.IsEmptyElement; + string str = xmlReader.ReadElementContentAsString(localName, namespaceURI); + if (isNull) + { + str = null; + } + return str; + } + /// /// Reads the content of a named element as an array of booleans. /// From c62bdcc083b61f5be0f759c99e3f8f23e6924399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Thu, 23 Jun 2022 22:57:37 +0200 Subject: [PATCH 35/39] Add tests for serialization of complex heterogenous structures. --- .../BinarySerializationTests.cs | 96 +- .../GraphMLSerializationTests.cs | 401 +++++- .../Helpers/TestHelpers.cs | 35 + .../SerializationTestCaseSources.cs | 429 +++++- .../TestClasses/SerializationTestClasses.cs | 8 +- .../SerializationTestEdgeClasses.cs | 66 +- .../SerializationTestVertexClasses.cs | 47 +- .../XmlSerializationTests.cs | 1176 ++++++++++++----- 8 files changed, 1822 insertions(+), 436 deletions(-) create mode 100644 tests/QuikGraph.Serialization.Tests/Helpers/TestHelpers.cs diff --git a/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs index 89cf2e64a..e7c49a3ad 100644 --- a/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs @@ -41,7 +41,7 @@ private static TGraph SerializeDeserialize([NotNull] TGr #endregion [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] - public void BinarySerialization_AdjacencyGraph([NotNull] AdjacencyGraph> graph) + public void BinarySerialization_AdjacencyGraph_Simple([NotNull] AdjacencyGraph> graph) { AdjacencyGraph> deserializedGraph1 = SerializeDeserialize, AdjacencyGraph>>(graph); @@ -53,8 +53,21 @@ public void BinarySerialization_AdjacencyGraph([NotNull] AdjacencyGraph graph) + { + AdjacencyGraph deserializedGraph1 = + SerializeDeserialize>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayAdjacencyGraph(graph); + ArrayAdjacencyGraph deserializedGraph2 = + SerializeDeserialize>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] - public void BinarySerialization_AdapterGraph([NotNull] AdjacencyGraph> graph) + public void BinarySerialization_AdapterGraph_Simple([NotNull] AdjacencyGraph> graph) { var bidirectionalAdapterGraph = new BidirectionalAdapterGraph>(graph); BidirectionalAdapterGraph> deserializedGraph = @@ -62,24 +75,49 @@ public void BinarySerialization_AdapterGraph([NotNull] AdjacencyGraph graph) + { + var bidirectionalAdapterGraph = new BidirectionalAdapterGraph(graph); + BidirectionalAdapterGraph deserializedGraph = + SerializeDeserialize>(bidirectionalAdapterGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphTestCases))] - public void BinarySerialization_ClusteredGraph([NotNull] ClusteredAdjacencyGraph> graph) + public void BinarySerialization_ClusteredGraph_Simple([NotNull] ClusteredAdjacencyGraph> graph) { ClusteredAdjacencyGraph> deserializedGraph = SerializeDeserialize, ClusteredAdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphComplexTestCases))] + public void BinarySerialization_ClusteredGraph_Complex([NotNull] ClusteredAdjacencyGraph graph) + { + ClusteredAdjacencyGraph deserializedGraph = + SerializeDeserialize>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphTestCases))] - public void BinarySerialization_CompressedGraph([NotNull] CompressedSparseRowGraph graph) + public void BinarySerialization_CompressedGraph_Simple([NotNull] CompressedSparseRowGraph graph) { CompressedSparseRowGraph deserializedGraph = SerializeDeserialize, CompressedSparseRowGraph>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphComplexTestCases))] + public void BinarySerialization_CompressedGraph_Complex([NotNull] CompressedSparseRowGraph graph) + { + CompressedSparseRowGraph deserializedGraph = + SerializeDeserialize, CompressedSparseRowGraph>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphTestCases))] - public void BinarySerialization_BidirectionalGraph([NotNull] BidirectionalGraph> graph) + public void BinarySerialization_BidirectionalGraph_Simple([NotNull] BidirectionalGraph> graph) { BidirectionalGraph> deserializedGraph = SerializeDeserialize, BidirectionalGraph>>(graph); @@ -101,6 +139,29 @@ public void BinarySerialization_BidirectionalGraph([NotNull] BidirectionalGraph< Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphComplexTestCases))] + public void BinarySerialization_BidirectionalGraph_Complex([NotNull] BidirectionalGraph graph) + { + BidirectionalGraph deserializedGraph = + SerializeDeserialize>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + + var arrayGraph = new ArrayBidirectionalGraph(graph); + ArrayBidirectionalGraph deserializedGraph2 = + SerializeDeserialize>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + + var reversedGraph = new ReversedBidirectionalGraph(graph); + ReversedBidirectionalGraph deserializedGraph3 = + SerializeDeserialize, ReversedBidirectionalGraph>(reversedGraph); + Assert.IsTrue(EquateGraphs.Equate(reversedGraph, deserializedGraph3)); + + var undirectedBidirectionalGraph = new UndirectedBidirectionalGraph(graph); + UndirectedBidirectionalGraph deserializedGraph4 = + SerializeDeserialize>(undirectedBidirectionalGraph); + Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); + } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalMatrixGraphTestCases))] public void BinarySerialization_BidirectionalMatrixGraph([NotNull] BidirectionalMatrixGraph> graph) { @@ -110,7 +171,7 @@ public void BinarySerialization_BidirectionalMatrixGraph([NotNull] Bidirectional } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphTestCases))] - public void BinarySerialization_UndirectedGraph([NotNull] UndirectedGraph> graph) + public void BinarySerialization_UndirectedGraph_Simple([NotNull] UndirectedGraph> graph) { UndirectedGraph> deserializedGraph1 = SerializeDeserialize, UndirectedGraph>>(graph); @@ -122,14 +183,35 @@ public void BinarySerialization_UndirectedGraph([NotNull] UndirectedGraph graph) + { + UndirectedGraph deserializedGraph1 = + SerializeDeserialize>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayUndirectedGraph(graph); + ArrayUndirectedGraph deserializedGraph2 = + SerializeDeserialize>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph2)); + } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphTestCases))] - public void BinarySerialization_EdgeListGraph([NotNull] EdgeListGraph> graph) + public void BinarySerialization_EdgeListGraph_Simple([NotNull] EdgeListGraph> graph) { EdgeListGraph> deserializedGraph = SerializeDeserialize, EdgeListGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphComplexTestCases))] + public void BinarySerialization_EdgeListGraph_Complex([NotNull] EdgeListGraph graph) + { + EdgeListGraph deserializedGraph = + SerializeDeserialize>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + #region Test classes public class TestStream : Stream diff --git a/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs b/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs index 91ca0d183..ad85debf4 100644 --- a/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/GraphMLSerializationTests.cs @@ -14,6 +14,7 @@ using QuikGraph.Tests; using static QuikGraph.Serialization.Tests.SerializationTestCaseSources; using static QuikGraph.Tests.QuikGraphUnitTestsHelpers; +using static QuikGraph.Serialization.Tests.TestHelpers; namespace QuikGraph.Serialization.Tests { @@ -182,7 +183,7 @@ public void SerializeToGraphML_Throws() var graph = new AdjacencyGraph(); Assert.Throws( - () => graph.SerializeToGraphML>((string)null)); + () => graph.SerializeToGraphML>((string)null)); Assert.Throws( () => graph.SerializeToGraphML>("")); @@ -227,10 +228,10 @@ public void SerializeToGraphML_Throws() using (XmlWriter writer = XmlWriter.Create(WriteThrowsTestFilePath)) { Assert.Throws( - () => ((AdjacencyGraph) null).SerializeToGraphML>(writer)); + () => ((AdjacencyGraph)null).SerializeToGraphML>(writer)); Assert.Throws( - () => ((AdjacencyGraph) null).SerializeToGraphML>( + () => ((AdjacencyGraph)null).SerializeToGraphML>( writer, vertex => vertex.ID, edge => edge.ID)); @@ -365,7 +366,7 @@ public void DeserializeFromGraphML_Throws() // ReSharper disable AssignNullToNotNullAttribute // Filepath Assert.Throws( - () => ((AdjacencyGraph>) null).DeserializeFromGraphML( + () => ((AdjacencyGraph>)null).DeserializeFromGraphML( GetGraphFilePath(TestGraphFileName), id => id, (source, target, _) => new Edge(source, target))); @@ -433,7 +434,7 @@ public void DeserializeFromGraphML_Throws() using (var reader = XmlReader.Create(GetGraphFilePath(TestGraphFileName))) { Assert.Throws( - () => ((AdjacencyGraph>) null).DeserializeFromGraphML( + () => ((AdjacencyGraph>)null).DeserializeFromGraphML( reader, id => id, (source, target, _) => new Edge(source, target))); @@ -558,7 +559,7 @@ private static string SerializeGraph1([NotNull] TestGraph graph) { string filePath = Path.Combine( GetTemporaryTestDirectory(), - $"serialization_to_graphml_test_{Guid.NewGuid().ToString()}.graphml"); + $"serialization_to_graphml_test_{Guid.NewGuid()}.graphml"); graph.SerializeToGraphML(filePath); Assert.IsTrue(File.Exists(filePath)); @@ -571,7 +572,7 @@ private static string SerializeGraph2([NotNull] TestGraph graph) { string filePath = Path.Combine( GetTemporaryTestDirectory(), - $"serialization_to_graphml_test_{Guid.NewGuid().ToString()}.graphml"); + $"serialization_to_graphml_test_{Guid.NewGuid()}.graphml"); graph.SerializeToGraphML( filePath, @@ -693,11 +694,10 @@ public void GraphMLSerializationWithValidation_WriteVertex( StringIList = StringsList }; - var vertex = new TestVertex("v1") + var vertex1 = new TestVertex("v1") { StringDefault = "bar", String = "string", - Int = 10, Long = 20, Float = 25.0F, Double = 30.0, @@ -706,7 +706,16 @@ public void GraphMLSerializationWithValidation_WriteVertex( IntIList = new[] { 4, 5, 6, 7 } }; - graph.AddVertex(vertex); + var vertex2 = new TestVertex("v2") + { + StringDefault = null, + String = "", + Int = 42, + IntArray = null + }; + + graph.AddVertex(vertex1); + graph.AddVertex(vertex2); TestGraph serializedGraph = VerifySerialization(graph, serializeGraph); @@ -729,16 +738,27 @@ public void GraphMLSerializationWithValidation_WriteVertex( CollectionAssert.AreEqual(graph.FloatIList, serializedGraph.FloatIList, new FloatComparer(0.001F)); CollectionAssert.AreEqual(graph.DoubleIList, serializedGraph.DoubleIList, new DoubleComparer(0.0001)); - TestVertex serializedVertex = serializedGraph.Vertices.First(); - Assert.AreEqual("bar", serializedVertex.StringDefault); - Assert.AreEqual(vertex.String, serializedVertex.String); - Assert.AreEqual(vertex.Int, serializedVertex.Int); - Assert.AreEqual(vertex.Long, serializedVertex.Long); - Assert.AreEqual(vertex.Float, serializedVertex.Float); - Assert.AreEqual(vertex.Double, serializedVertex.Double); - Assert.AreEqual(vertex.Bool, serializedVertex.Bool); - CollectionAssert.AreEqual(vertex.IntArray, serializedVertex.IntArray); - CollectionAssert.AreEqual(vertex.IntIList, serializedVertex.IntIList); + TestVertex serializedVertex1 = serializedGraph.Vertices.First(); + Assert.AreEqual(vertex1.StringDefault, serializedVertex1.StringDefault); + Assert.AreEqual(vertex1.String, serializedVertex1.String); + Assert.AreEqual(vertex1.Int, serializedVertex1.Int); + Assert.AreEqual(vertex1.Long, serializedVertex1.Long); + Assert.AreEqual(vertex1.Float, serializedVertex1.Float); + Assert.AreEqual(vertex1.Double, serializedVertex1.Double); + Assert.AreEqual(vertex1.Bool, serializedVertex1.Bool); + CollectionAssert.AreEqual(vertex1.IntArray, serializedVertex1.IntArray); + CollectionAssert.AreEqual(vertex1.IntIList, serializedVertex1.IntIList); + + TestVertex serializedVertex2 = serializedGraph.Vertices.Last(); + Assert.AreEqual(vertex2.StringDefault, serializedVertex2.StringDefault); + Assert.AreEqual(vertex2.String, serializedVertex2.String); + Assert.AreEqual(vertex2.Int, serializedVertex2.Int); + Assert.AreEqual(vertex2.Long, serializedVertex2.Long); + Assert.AreEqual(vertex2.Float, serializedVertex2.Float); + Assert.AreEqual(vertex2.Double, serializedVertex2.Double); + Assert.AreEqual(vertex2.Bool, serializedVertex2.Bool); + CollectionAssert.AreEqual(vertex2.IntArray, serializedVertex2.IntArray); + CollectionAssert.AreEqual(vertex2.IntIList, serializedVertex2.IntIList); } [TestCaseSource(nameof(GraphSerializationTestCases))] @@ -781,7 +801,7 @@ public void GraphMLSerializationWithValidation_WriteEdge( graph.AddVertex(vertex1); graph.AddVertex(vertex2); - var edge = new TestEdge( + var edge1 = new TestEdge( vertex1, vertex2, "e1", "edge", @@ -791,19 +811,40 @@ public void GraphMLSerializationWithValidation_WriteEdge( 110.0, true); - graph.AddEdge(edge); + var edge2 = new TestEdge(vertex1, vertex2, "e2") + { + Float = 13.4f, + Long = 42L + }; + + graph.AddEdge(edge1); + graph.AddEdge(edge2); TestGraph serializedGraph = VerifySerialization(graph, serializeGraph); - TestEdge serializedEdge = serializedGraph.Edges.First(); + TestEdge serializedEdge1 = serializedGraph.Edges.First(); if (keepIds) - Assert.AreEqual(edge.ID, serializedEdge.ID); - Assert.AreEqual(edge.String, serializedEdge.String); - Assert.AreEqual(edge.Int, serializedEdge.Int); - Assert.AreEqual(edge.Long, serializedEdge.Long); - Assert.AreEqual(edge.Float, serializedEdge.Float); - Assert.AreEqual(edge.Double, serializedEdge.Double); - Assert.AreEqual(edge.Bool, serializedEdge.Bool); + { + Assert.AreEqual(edge1.ID, serializedEdge1.ID); + } + Assert.AreEqual(edge1.String, serializedEdge1.String); + Assert.AreEqual(edge1.Int, serializedEdge1.Int); + Assert.AreEqual(edge1.Long, serializedEdge1.Long); + Assert.AreEqual(edge1.Float, serializedEdge1.Float); + Assert.AreEqual(edge1.Double, serializedEdge1.Double); + Assert.AreEqual(edge1.Bool, serializedEdge1.Bool); + + TestEdge serializedEdge2 = serializedGraph.Edges.Last(); + if (keepIds) + { + Assert.AreEqual(edge2.ID, serializedEdge2.ID); + } + Assert.AreEqual(edge2.String, serializedEdge2.String); + Assert.AreEqual(edge2.Int, serializedEdge2.Int); + Assert.AreEqual(edge2.Long, serializedEdge2.Long); + Assert.AreEqual(edge2.Float, serializedEdge2.Float); + Assert.AreEqual(edge2.Double, serializedEdge2.Double); + Assert.AreEqual(edge2.Bool, serializedEdge2.Bool); } [Test] @@ -847,15 +888,57 @@ public void DeserializeAndValidateFromGraphML_Throws() #region Serialization/Deserialization + #region Test Helpers + + [Pure] + private static int DeserializeVertex_Simple([NotNull] string id) + { + return int.Parse(id); + } + [Pure] [NotNull] - private static TOutGraph SerializeDeserialize( + private static EquatableEdge DeserializeEdge_Simple(int source, int target, [NotNull] string id) + { + return new EquatableEdge(source, target); + } + + [Pure] + private static SEquatableEdge DeserializeSEdge_Simple(int source, int target, [NotNull] string id) + { + return new SEquatableEdge(source, target); + } + + [Pure] + [NotNull] + private static EquatableTestVertex DeserializeVertex_Complex([NotNull] string id) + { + return new EquatableTestVertex(id); + } + + [Pure] + [NotNull] + private static EquatableTestEdge DeserializeEdge_Complex([NotNull] EquatableTestVertex source, [NotNull] EquatableTestVertex target, [NotNull] string id) + { + return new EquatableTestEdge(source, target, id); + } + + [Pure] + private static SEquatableEdge DeserializeSEdge_Complex([NotNull] EquatableTestVertex source, [NotNull] EquatableTestVertex target, [NotNull] string id) + { + return new SEquatableEdge(source, target); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize( [NotNull] TInGraph graph, + [NotNull, InstantHandle] VertexIdentity vertexIdentity, [NotNull, InstantHandle] Func deserialize) - where TInEdge : IEdge, IEquatable - where TOutEdge : IEdge, IEquatable - where TInGraph : IEdgeListGraph - where TOutGraph : IEdgeListGraph + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph { Assert.IsNotNull(graph); @@ -866,11 +949,10 @@ private static TOutGraph SerializeDeserialize vertex.ToString(), + vertexIdentity, graph.GetEdgeIdentity()); } - // Deserialize stream.Position = 0; // Deserialize @@ -886,120 +968,278 @@ private static TOutGraph SerializeDeserialize([NotNull] TInGraph graph) + private static TOutGraph SerializeDeserialize_Simple( + [NotNull] TInGraph graph, + [NotNull, InstantHandle] Func deserialize) + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph + { + return SerializeDeserialize( + graph, + VertexIdentity_Simple, + deserialize); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Complex( + [NotNull] TInGraph graph, + [NotNull, InstantHandle] Func deserialize) + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph + { + return SerializeDeserialize( + graph, + VertexIdentity_Complex, + deserialize); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Simple([NotNull] TInGraph graph) where TInGraph : IEdgeListGraph> where TOutGraph : class, IMutableVertexAndEdgeSet>, new() { - return SerializeDeserialize, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + return SerializeDeserialize_Simple, EquatableEdge, TInGraph, TOutGraph>(graph, reader => { var deserializedGraph = new TOutGraph(); deserializedGraph.DeserializeFromGraphML( reader, - int.Parse, - (source, target, _) => new EquatableEdge(source, target)); + DeserializeVertex_Simple, + DeserializeEdge_Simple); return deserializedGraph; }); } [Pure] [NotNull] - private static TOutGraph SerializeDeserialize_SEdge([NotNull] TInGraph graph) + private static TOutGraph SerializeDeserialize_Complex([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph + where TOutGraph : class, IMutableVertexAndEdgeSet, new() + { + return SerializeDeserialize_Complex(graph, reader => + { + var deserializedGraph = new TOutGraph(); + deserializedGraph.DeserializeFromGraphML( + reader, + DeserializeVertex_Complex, + DeserializeEdge_Complex); + return deserializedGraph; + }); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_SEdge_Simple([NotNull] TInGraph graph) where TInGraph : IEdgeListGraph> where TOutGraph : class, IMutableVertexAndEdgeSet>, new() { - return SerializeDeserialize, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => + return SerializeDeserialize_Simple, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => { var deserializedGraph = new TOutGraph(); deserializedGraph.DeserializeFromGraphML( reader, - int.Parse, - (source, target, _) => new SEquatableEdge(source, target)); + DeserializeVertex_Simple, + DeserializeSEdge_Simple); return deserializedGraph; }); } [Pure] [NotNull] - private static TOutGraph SerializeDeserialize_Reversed([NotNull] TInGraph graph) + private static TOutGraph SerializeDeserialize_SEdge_Complex([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + return SerializeDeserialize_Complex, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => + { + var deserializedGraph = new TOutGraph(); + deserializedGraph.DeserializeFromGraphML( + reader, + DeserializeVertex_Complex, + DeserializeSEdge_Complex); + return deserializedGraph; + }); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Reversed_Simple([NotNull] TInGraph graph) where TInGraph : IEdgeListGraph>> where TOutGraph : class, IMutableVertexAndEdgeSet>, new() { - return SerializeDeserialize>, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + return SerializeDeserialize_Simple>, EquatableEdge, TInGraph, TOutGraph>(graph, reader => { var deserializedGraph = new TOutGraph(); deserializedGraph.DeserializeFromGraphML( reader, - int.Parse, - (source, target, _) => new EquatableEdge(source, target)); + DeserializeVertex_Simple, + DeserializeEdge_Simple); return deserializedGraph; }); } + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Reversed_Complex([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet, new() + { + return SerializeDeserialize_Complex, EquatableTestEdge, TInGraph, TOutGraph>(graph, reader => + { + var deserializedGraph = new TOutGraph(); + deserializedGraph.DeserializeFromGraphML( + reader, + DeserializeVertex_Complex, + DeserializeEdge_Complex); + return deserializedGraph; + }); + } + + #endregion + + // TODO Support heterogeneous types for vertices and edges + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] - public void GraphMLSerialization_AdjacencyGraph([NotNull] AdjacencyGraph> graph) + public void GraphMLSerialization_AdjacencyGraph_Simple([NotNull] AdjacencyGraph> graph) { AdjacencyGraph> deserializedGraph1 = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); var arrayGraph = new ArrayAdjacencyGraph>(graph); AdjacencyGraph> deserializedGraph2 = - SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphComplexNotHeterogeneousTestCases))] + public void GraphMLSerialization_AdjacencyGraph_Complex([NotNull] AdjacencyGraph graph) + { + AdjacencyGraph deserializedGraph1 = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayAdjacencyGraph(graph); + AdjacencyGraph deserializedGraph2 = + SerializeDeserialize_Complex, AdjacencyGraph>(arrayGraph); Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] - public void GraphMLSerialization_AdapterGraph([NotNull] AdjacencyGraph> graph) + public void GraphMLSerialization_AdapterGraph_Simple([NotNull] AdjacencyGraph> graph) { var bidirectionalAdapterGraph = new BidirectionalAdapterGraph>(graph); AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(bidirectionalAdapterGraph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(bidirectionalAdapterGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphComplexNotHeterogeneousTestCases))] + public void GraphMLSerialization_AdapterGraph_Complex([NotNull] AdjacencyGraph graph) + { + var bidirectionalAdapterGraph = new BidirectionalAdapterGraph(graph); + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(bidirectionalAdapterGraph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphTestCases))] - public void GraphMLSerialization_ClusteredGraph([NotNull] ClusteredAdjacencyGraph> graph) + public void GraphMLSerialization_ClusteredGraph_Simple([NotNull] ClusteredAdjacencyGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphComplexNotHeterogeneousTestCases))] + public void GraphMLSerialization_ClusteredGraph_Complex([NotNull] ClusteredAdjacencyGraph graph) + { + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphTestCases))] - public void GraphMLSerialization_CompressedGraph([NotNull] CompressedSparseRowGraph graph) + public void GraphMLSerialization_CompressedGraph_Simple([NotNull] CompressedSparseRowGraph graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize_SEdge, AdjacencyGraph>>(graph); + SerializeDeserialize_SEdge_Simple, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphComplexNotHeterogeneousTestCases))] + public void GraphMLSerialization_CompressedGraph_Complex([NotNull] CompressedSparseRowGraph graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize_SEdge_Complex, AdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphTestCases))] - public void GraphMLSerialization_BidirectionalGraph([NotNull] BidirectionalGraph> graph) + public void GraphMLSerialization_BidirectionalGraph_Simple([NotNull] BidirectionalGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); var arrayGraph = new ArrayBidirectionalGraph>(graph); AdjacencyGraph> deserializedGraph2 = - SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(arrayGraph); Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); var reversedGraph = new ReversedBidirectionalGraph>(graph); BidirectionalGraph> deserializedGraph3 = - SerializeDeserialize_Reversed>, BidirectionalGraph>>(reversedGraph); + SerializeDeserialize_Reversed_Simple>, BidirectionalGraph>>(reversedGraph); Assert.IsTrue( EquateGraphs.Equate( graph, deserializedGraph3, EqualityComparer.Default, LambdaEqualityComparer>.Create( - (edge1, edge2) => Equals(edge1.Source, edge2.Target) && Equals(edge1.Target, edge2.Source), + (edge1, edge2) => Equals(edge1.Source, edge2.Target) + && Equals(edge1.Target, edge2.Source) + && edge1.GetType() == edge2.GetType(), edge => edge.GetHashCode()))); var undirectedBidirectionalGraph = new UndirectedBidirectionalGraph>(graph); UndirectedGraph> deserializedGraph4 = - SerializeDeserialize>, UndirectedGraph>>(undirectedBidirectionalGraph); + SerializeDeserialize_Simple>, UndirectedGraph>>(undirectedBidirectionalGraph); + Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphComplexNotHeterogeneousTestCases))] + public void GraphMLSerialization_BidirectionalGraph_Complex([NotNull] BidirectionalGraph graph) + { + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + + var arrayGraph = new ArrayBidirectionalGraph(graph); + AdjacencyGraph deserializedGraph2 = + SerializeDeserialize_Complex, AdjacencyGraph>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + + var reversedGraph = new ReversedBidirectionalGraph(graph); + BidirectionalGraph deserializedGraph3 = + SerializeDeserialize_Reversed_Complex, BidirectionalGraph>(reversedGraph); + Assert.IsTrue( + EquateGraphs.Equate( + graph, + deserializedGraph3, + EqualityComparer.Default, + LambdaEqualityComparer.Create( + // TODO SReversedEdge original edge is not parsed by the serializer so data are not serialized + (edge1, edge2) => Equals(edge1.Source, edge2.Target) && Equals(edge1.Target, edge2.Source)/* && edge1.DataContentEquals(edge2)*/, + edge => edge.GetHashCode()))); + + var undirectedBidirectionalGraph = new UndirectedBidirectionalGraph(graph); + UndirectedGraph deserializedGraph4 = + SerializeDeserialize_Complex, UndirectedGraph>(undirectedBidirectionalGraph); Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); } @@ -1007,28 +1247,49 @@ public void GraphMLSerialization_BidirectionalGraph([NotNull] BidirectionalGraph public void GraphMLSerialization_BidirectionalMatrixGraph([NotNull] BidirectionalMatrixGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphTestCases))] - public void GraphMLSerialization_UndirectedGraph([NotNull] UndirectedGraph> graph) + public void GraphMLSerialization_UndirectedGraph_Simple([NotNull] UndirectedGraph> graph) { UndirectedGraph> deserializedGraph1 = - SerializeDeserialize>, UndirectedGraph>>(graph); + SerializeDeserialize_Simple>, UndirectedGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); var arrayGraph = new ArrayUndirectedGraph>(graph); UndirectedGraph> deserializedGraph2 = - SerializeDeserialize>, UndirectedGraph>>(arrayGraph); + SerializeDeserialize_Simple>, UndirectedGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphComplexNotHeterogeneousTestCases))] + public void GraphMLSerialization_UndirectedGraph_Complex([NotNull] UndirectedGraph graph) + { + UndirectedGraph deserializedGraph1 = + SerializeDeserialize_Complex, UndirectedGraph>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayUndirectedGraph(graph); + UndirectedGraph deserializedGraph2 = + SerializeDeserialize_Complex, UndirectedGraph>(arrayGraph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph2)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphTestCases))] - public void GraphMLSerialization_EdgeListGraph([NotNull] EdgeListGraph> graph) + public void GraphMLSerialization_EdgeListGraph_Simple([NotNull] EdgeListGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphComplexNotHeterogeneousTestCases))] + public void GraphMLSerialization_EdgeListGraph_Complex([NotNull] EdgeListGraph graph) + { + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } diff --git a/tests/QuikGraph.Serialization.Tests/Helpers/TestHelpers.cs b/tests/QuikGraph.Serialization.Tests/Helpers/TestHelpers.cs new file mode 100644 index 000000000..a32d50262 --- /dev/null +++ b/tests/QuikGraph.Serialization.Tests/Helpers/TestHelpers.cs @@ -0,0 +1,35 @@ +using System; +using JetBrains.Annotations; + +namespace QuikGraph.Serialization.Tests +{ + /// + /// Various helpers for Serialization tests. + /// + internal static class TestHelpers + { + /// + /// Converts a into a string representation for easy serialization. + /// + [Pure] + [NotNull] + public static string TypeToSerializableType([NotNull] Type type) + { + return $"{type.FullName}, {type.Assembly.GetName().Name}"; + } + + [Pure] + [NotNull] + public static string VertexIdentity_Simple(int vertex) + { + return vertex.ToString(); + } + + [Pure] + [NotNull] + public static string VertexIdentity_Complex([NotNull] EquatableTestVertex vertex) + { + return vertex.ID; + } + } +} \ No newline at end of file diff --git a/tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs b/tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs index 553fe222a..a3da56ec8 100644 --- a/tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs +++ b/tests/QuikGraph.Serialization.Tests/SerializationTestCaseSources.cs @@ -19,14 +19,43 @@ public static IEnumerable SerializationAdjacencyGraphTestCases yield return new TestCaseData(emptyGraph); var graph = new AdjacencyGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddVertexRange(new[] { 0, 1, 2, 3, 4 }); graph.AddEdgeRange(new[] { new EquatableEdge(0, 1), new EquatableEdge(1, 2), new EquatableEdge(2, 0), new EquatableEdge(2, 1), - new EquatableEdge(2, 2) + new EquatableEdge(2, 2), + new EquatableEdge(4, 2) + }); + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationAdjacencyGraphComplexTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new AdjacencyGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableAdditionalDataTestVertex("2", 25.0) { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableAdditionalDataTestVertex("4", 42.0); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableAdditionalDataTestEdge(vertex1, vertex3, "1", 12.0) { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableAdditionalDataTestEdge(vertex3, vertex4, "4", 45.5) }); yield return new TestCaseData(graph); } @@ -43,14 +72,15 @@ public static IEnumerable SerializationClusteredAdjacencyGraphTest yield return new TestCaseData(clusterEmptyGraph); var graph = new AdjacencyGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddVertexRange(new[] { 0, 1, 2, 3, 4 }); graph.AddEdgeRange(new[] { new EquatableEdge(0, 1), new EquatableEdge(1, 2), new EquatableEdge(2, 0), new EquatableEdge(2, 1), - new EquatableEdge(2, 2) + new EquatableEdge(2, 2), + new EquatableEdge(4, 2) }); var clusterGraph = new ClusteredAdjacencyGraph>(graph); yield return new TestCaseData(clusterGraph); @@ -72,6 +102,53 @@ public static IEnumerable SerializationClusteredAdjacencyGraphTest } } + [NotNull, ItemNotNull] + public static IEnumerable SerializationClusteredAdjacencyGraphComplexTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph(); + var clusterEmptyGraph = new ClusteredAdjacencyGraph(emptyGraph); + yield return new TestCaseData(clusterEmptyGraph); + + var graph = new AdjacencyGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableAdditionalDataTestVertex("2", 25.0) { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableAdditionalDataTestVertex("4", 42.0); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableAdditionalDataTestEdge(vertex1, vertex3, "1", 12.0) { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableAdditionalDataTestEdge(vertex3, vertex4, "4", 45.5) + }); + var clusterGraph = new ClusteredAdjacencyGraph(graph); + yield return new TestCaseData(clusterGraph); + + graph = new AdjacencyGraph(); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex0, vertex1, "0"), + new EquatableTestEdge(vertex1, vertex2, "1") { Long = 66L }, + new EquatableTestEdge(vertex2, vertex0, "2"), + new EquatableTestEdge(vertex3, vertex2, "3") + }); + clusterGraph = new ClusteredAdjacencyGraph(graph); + ClusteredAdjacencyGraph subGraph = clusterGraph.AddCluster(); + var vertex5 = new EquatableTestVertex("5"); + var vertex6 = new EquatableAdditionalDataTestVertex("6", 45.0) { Double = 22.9 }; + subGraph.AddVertexRange(new[] { vertex4, vertex5, vertex6 }); + subGraph.AddEdge(new EquatableTestEdge(vertex4, vertex6, "4")); + yield return new TestCaseData(clusterGraph); + } + } + [NotNull, ItemNotNull] public static IEnumerable SerializationCompressedGraphTestCases { @@ -83,20 +160,51 @@ public static IEnumerable SerializationCompressedGraphTestCases yield return new TestCaseData(emptyCompressedGraph); var graph = new AdjacencyGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddVertexRange(new[] { 0, 1, 2, 3, 4 }); graph.AddEdgeRange(new[] { new EquatableEdge(0, 1), new EquatableEdge(1, 2), new EquatableEdge(2, 0), new EquatableEdge(2, 1), - new EquatableEdge(2, 2) + new EquatableEdge(2, 2), + new EquatableEdge(4, 2) }); var compressedGraph = CompressedSparseRowGraph.FromGraph(emptyGraph); yield return new TestCaseData(compressedGraph); } } + [NotNull, ItemNotNull] + public static IEnumerable SerializationCompressedGraphComplexTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph(); + var emptyCompressedGraph = CompressedSparseRowGraph.FromGraph(emptyGraph); + yield return new TestCaseData(emptyCompressedGraph); + + var graph = new AdjacencyGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableAdditionalDataTestVertex("2", 25.0) { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableAdditionalDataTestVertex("4", 42.0); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableAdditionalDataTestEdge(vertex1, vertex3, "1", 12.0) { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableAdditionalDataTestEdge(vertex3, vertex4, "4", 45.5) + }); + var compressedGraph = CompressedSparseRowGraph.FromGraph(graph); + yield return new TestCaseData(compressedGraph); + } + } + [NotNull, ItemNotNull] public static IEnumerable SerializationBidirectionalGraphTestCases { @@ -107,14 +215,44 @@ public static IEnumerable SerializationBidirectionalGraphTestCases yield return new TestCaseData(emptyGraph); var graph = new BidirectionalGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddVertexRange(new[] { 0, 1, 2, 3, 4 }); graph.AddEdgeRange(new[] { new EquatableEdge(0, 1), new EquatableEdge(1, 2), new EquatableEdge(2, 0), new EquatableEdge(2, 1), - new EquatableEdge(2, 2) + new EquatableEdge(2, 2), + new EquatableEdge(4, 2) + }); + + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationBidirectionalGraphComplexTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new BidirectionalGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new BidirectionalGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableAdditionalDataTestVertex("2", 25.0) { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableAdditionalDataTestVertex("4", 42.0); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableAdditionalDataTestEdge(vertex1, vertex3, "1", 12.0) { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableAdditionalDataTestEdge(vertex3, vertex4, "4", 45.5) }); yield return new TestCaseData(graph); @@ -130,14 +268,27 @@ public static IEnumerable SerializationBidirectionalMatrixGraphTes var emptyGraph = new BidirectionalMatrixGraph>(10); yield return new TestCaseData(emptyGraph); - var graph = new BidirectionalMatrixGraph>(4); + var graph = new BidirectionalMatrixGraph>(5); graph.AddEdgeRange(new[] { new EquatableEdge(0, 1), new EquatableEdge(1, 2), new EquatableEdge(2, 0), new EquatableEdge(2, 1), - new EquatableEdge(2, 2) + new EquatableEdge(2, 2), + new EquatableEdge(4, 2) + }); + + yield return new TestCaseData(graph); + + graph = new BidirectionalMatrixGraph>(5); + graph.AddEdgeRange(new[] + { + new EquatableTaggedEdge(1, 2, "test"), + new EquatableEdge(1, 3), + new EquatableTaggedEdge(1, 4, 42.0), + new EquatableEdge(2, 2), + new EquatableEdge(3, 4) }); yield return new TestCaseData(graph); @@ -154,14 +305,44 @@ public static IEnumerable SerializationUndirectedGraphTestCases yield return new TestCaseData(emptyGraph); var graph = new UndirectedGraph>(); - graph.AddVertexRange(new[] { 0, 1, 2, 3 }); + graph.AddVertexRange(new[] { 0, 1, 2, 3, 4 }); graph.AddEdgeRange(new[] { new EquatableEdge(0, 1), new EquatableEdge(1, 2), new EquatableEdge(2, 0), new EquatableEdge(2, 1), - new EquatableEdge(2, 2) + new EquatableEdge(2, 2), + new EquatableEdge(4, 2) + }); + + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationUndirectedGraphComplexTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new UndirectedGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new UndirectedGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableAdditionalDataTestVertex("2", 25.0) { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableAdditionalDataTestVertex("4", 42.0); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableAdditionalDataTestEdge(vertex1, vertex3, "1", 12.0) { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableAdditionalDataTestEdge(vertex3, vertex4, "4", 45.5) }); yield return new TestCaseData(graph); @@ -184,11 +365,233 @@ public static IEnumerable SerializationEdgeListGraphTestCases new EquatableEdge(1, 2), new EquatableEdge(2, 0), new EquatableEdge(2, 1), - new EquatableEdge(2, 2) + new EquatableEdge(2, 2), + new EquatableEdge(4, 2) }); yield return new TestCaseData(graph); } } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationEdgeListGraphComplexTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new EdgeListGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new EdgeListGraph(); + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableAdditionalDataTestVertex("2", 25.0) { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableAdditionalDataTestVertex("4", 42.0) { String = "", StringDefault = null }; + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableAdditionalDataTestEdge(vertex1, vertex3, "1", 12.0) { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableAdditionalDataTestEdge(vertex3, vertex4, "4", 45.5) + }); + + yield return new TestCaseData(graph); + } + } + + #region GraphML Test cases + + [NotNull, ItemNotNull] + public static IEnumerable SerializationAdjacencyGraphComplexNotHeterogeneousTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new AdjacencyGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableTestVertex("2") { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableTestVertex("4"); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableTestEdge(vertex1, vertex3, "1") { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableTestEdge(vertex3, vertex4, "4") + }); + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationClusteredAdjacencyGraphComplexNotHeterogeneousTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph(); + var clusterEmptyGraph = new ClusteredAdjacencyGraph(emptyGraph); + yield return new TestCaseData(clusterEmptyGraph); + + var graph = new AdjacencyGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableTestVertex("2") { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableTestVertex("4"); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableTestEdge(vertex1, vertex3, "1") { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableTestEdge(vertex3, vertex4, "4") + }); + var clusterGraph = new ClusteredAdjacencyGraph(graph); + yield return new TestCaseData(clusterGraph); + + graph = new AdjacencyGraph(); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex0, vertex1, "0"), + new EquatableTestEdge(vertex1, vertex2, "1") { Long = 66L }, + new EquatableTestEdge(vertex2, vertex0, "2"), + new EquatableTestEdge(vertex3, vertex2, "3") + }); + clusterGraph = new ClusteredAdjacencyGraph(graph); + ClusteredAdjacencyGraph subGraph = clusterGraph.AddCluster(); + var vertex5 = new EquatableTestVertex("5"); + var vertex6 = new EquatableTestVertex("6") { Double = 22.9 }; + subGraph.AddVertexRange(new[] { vertex4, vertex5, vertex6 }); + subGraph.AddEdge(new EquatableTestEdge(vertex4, vertex6, "4")); + yield return new TestCaseData(clusterGraph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationCompressedGraphComplexNotHeterogeneousTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new AdjacencyGraph(); + var emptyCompressedGraph = CompressedSparseRowGraph.FromGraph(emptyGraph); + yield return new TestCaseData(emptyCompressedGraph); + + var graph = new AdjacencyGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableTestVertex("2") { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableTestVertex("4"); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableTestEdge(vertex1, vertex3, "1") { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableTestEdge(vertex3, vertex4, "4") + }); + var compressedGraph = CompressedSparseRowGraph.FromGraph(graph); + yield return new TestCaseData(compressedGraph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationBidirectionalGraphComplexNotHeterogeneousTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new BidirectionalGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new BidirectionalGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableTestVertex("2") { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableTestVertex("4"); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableTestEdge(vertex1, vertex3, "1") { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableTestEdge(vertex3, vertex4, "4") + }); + + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationUndirectedGraphComplexNotHeterogeneousTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new UndirectedGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new UndirectedGraph(); + var vertex0 = new EquatableTestVertex("0") { String = "", StringDefault = null }; + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableTestVertex("2") { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableTestVertex("4"); + graph.AddVertexRange(new[] { vertex0, vertex1, vertex2, vertex3, vertex4 }); + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableTestEdge(vertex1, vertex3, "1") { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableTestEdge(vertex3, vertex4, "4") + }); + + yield return new TestCaseData(graph); + } + } + + [NotNull, ItemNotNull] + public static IEnumerable SerializationEdgeListGraphComplexNotHeterogeneousTestCases + { + [UsedImplicitly] + get + { + var emptyGraph = new EdgeListGraph(); + yield return new TestCaseData(emptyGraph); + + var graph = new EdgeListGraph(); + var vertex1 = new EquatableTestVertex("1") { Float = 1.3f, String = "test" }; + var vertex2 = new EquatableTestVertex("2") { Double = 12.5, Bool = true }; + var vertex3 = new EquatableTestVertex("3") { Int = 45, Long = 51L }; + var vertex4 = new EquatableTestVertex("4") { String = "", StringDefault = null }; + graph.AddEdgeRange(new[] + { + new EquatableTestEdge(vertex1, vertex2, "0") { Bool = true, Int = 77 }, + new EquatableTestEdge(vertex1, vertex3, "1") { Long = 99L }, + new EquatableTestEdge(vertex1, vertex4, "2") { String = "test" }, + new EquatableTestEdge(vertex2, vertex2, "3"), + new EquatableTestEdge(vertex3, vertex4, "4") + }); + + yield return new TestCaseData(graph); + } + } + + #endregion } } \ No newline at end of file diff --git a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestClasses.cs b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestClasses.cs index 1123365e5..0d66d1b32 100644 --- a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestClasses.cs +++ b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestClasses.cs @@ -68,7 +68,7 @@ public enum AgeGroup #if SUPPORTS_SERIALIZATION [Serializable] #endif - public class Person : INotifyPropertyChanged, IEquatable, IDataErrorInfo + public sealed class Person : INotifyPropertyChanged, IEquatable, IDataErrorInfo { #region Fields and Constants @@ -519,7 +519,7 @@ public string BirthPlace [XmlIgnore] public string BirthMonthAndDay => _birthDate?.ToString( - DateTimeFormatInfo.CurrentInfo?.MonthDayPattern, + DateTimeFormatInfo.CurrentInfo.MonthDayPattern, CultureInfo.CurrentCulture); /// @@ -538,7 +538,7 @@ public string BirthDateAndPlace returnValue.Append("Born "); returnValue.Append( _birthDate.Value.ToString( - DateTimeFormatInfo.CurrentInfo?.ShortDatePattern, + DateTimeFormatInfo.CurrentInfo.ShortDatePattern, CultureInfo.CurrentCulture)); if (!string.IsNullOrEmpty(_birthPlace)) @@ -649,7 +649,7 @@ public bool IsLiving /// Fires the event for the property when it changes. /// /// Property name. - protected virtual void OnPropertyChanged([NotNull] string propertyName) + private void OnPropertyChanged([NotNull] string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } diff --git a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs index 9517ce1a6..6fac951f4 100644 --- a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs +++ b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestEdgeClasses.cs @@ -64,7 +64,10 @@ public TestEdge( public float Float { get; set; } } - public sealed class EquatableTestEdge : Edge, IEquatable +#if SUPPORTS_SERIALIZATION + [Serializable] +#endif + public class EquatableTestEdge : EquatableEdge, IEquatable { public EquatableTestEdge( [NotNull] EquatableTestVertex source, @@ -99,13 +102,10 @@ public EquatableTestEdge( [XmlAttribute("e_float")] public float Float { get; set; } - public bool Equals(EquatableTestEdge other) + public virtual bool DataContentEquals([NotNull] EquatableTestEdge other) { - if (other is null) - return false; - if (ReferenceEquals(this, other)) - return true; - return string.Equals(ID, other.ID) + return GetType() == other.GetType() + && string.Equals(ID, other.ID) && string.Equals(String, other.String) && Int == other.Int && Long == other.Long @@ -114,6 +114,15 @@ public bool Equals(EquatableTestEdge other) && Float.Equals(other.Float); } + public bool Equals(EquatableTestEdge other) + { + if (other is null) + return false; + if (ReferenceEquals(this, other)) + return true; + return base.Equals(other) && DataContentEquals(other); + } + public override bool Equals(object obj) { return Equals(obj as EquatableTestEdge); @@ -136,6 +145,49 @@ public override int GetHashCode() } } +#if SUPPORTS_SERIALIZATION + [Serializable] +#endif + public sealed class EquatableAdditionalDataTestEdge : EquatableTestEdge, IEquatable + { + public EquatableAdditionalDataTestEdge( + [NotNull] EquatableTestVertex source, + [NotNull] EquatableTestVertex target, + [NotNull] string id, + double data) + : base(source, target, id) + { + Data = data; + } + + public double Data { get; } + + public override bool DataContentEquals(EquatableTestEdge other) + { + return base.DataContentEquals(other) && Data.Equals(((EquatableAdditionalDataTestEdge)other).Data); + } + + public bool Equals(EquatableAdditionalDataTestEdge other) + { + return base.Equals(other); + } + + public override bool Equals(object obj) + { + return Equals(obj as EquatableAdditionalDataTestEdge); + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = ID.GetHashCode(); + hashCode = (hashCode * 397) ^ (Data.GetHashCode()); + return hashCode; + } + } + } + public sealed class TestEdgeNoSetter : Edge { public TestEdgeNoSetter( diff --git a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs index 57d6b950f..375949749 100644 --- a/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs +++ b/tests/QuikGraph.Serialization.Tests/TestClasses/SerializationTestVertexClasses.cs @@ -9,6 +9,9 @@ namespace QuikGraph.Serialization.Tests { #region Test classes +#if SUPPORTS_SERIALIZATION + [Serializable] +#endif public class TestVertex { public TestVertex([NotNull] string id) @@ -21,7 +24,7 @@ public TestVertex([NotNull] string id) [XmlAttribute("v_stringDefault")] [DefaultValue("defaultDefaultString")] - public string StringDefault { get; set; } + public string StringDefault { get; set; } = string.Empty; [XmlAttribute("v_string")] [DefaultValue("defaultString")] @@ -51,7 +54,10 @@ public TestVertex([NotNull] string id) public IList IntIList { get; set; } } - public sealed class EquatableTestVertex : TestVertex, IEquatable +#if SUPPORTS_SERIALIZATION + [Serializable] +#endif + public class EquatableTestVertex : TestVertex, IEquatable { public EquatableTestVertex([NotNull] string id) : base(id) @@ -64,6 +70,8 @@ public bool Equals(EquatableTestVertex other) return false; if (ReferenceEquals(this, other)) return true; + if (GetType() != other.GetType()) + return false; return string.Equals(ID, other.ID) && string.Equals(StringDefault, other.StringDefault) && string.Equals(String, other.String) @@ -101,5 +109,40 @@ public override int GetHashCode() } } +#if SUPPORTS_SERIALIZATION + [Serializable] +#endif + public sealed class EquatableAdditionalDataTestVertex : EquatableTestVertex, IEquatable + { + public EquatableAdditionalDataTestVertex([NotNull] string id, double data) + : base(id) + { + Data = data; + } + + public double Data { get; } + + public bool Equals(EquatableAdditionalDataTestVertex other) + { + // ReSharper disable once PossibleNullReferenceException + return base.Equals(other) && Data.Equals(other.Data); + } + + public override bool Equals(object obj) + { + return Equals(obj as EquatableAdditionalDataTestVertex); + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = ID.GetHashCode(); + hashCode = (hashCode * 397) ^ (Data.GetHashCode()); + return hashCode; + } + } + } + #endregion } \ No newline at end of file diff --git a/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs b/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs index 576e74fb0..bda04688b 100644 --- a/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/XmlSerializationTests.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -11,6 +12,7 @@ using static QuikGraph.Tests.GraphTestHelpers; using static QuikGraph.Tests.QuikGraphUnitTestsHelpers; using static QuikGraph.Serialization.Tests.SerializationTestCaseSources; +using static QuikGraph.Serialization.Tests.TestHelpers; namespace QuikGraph.Serialization.Tests { @@ -20,23 +22,100 @@ namespace QuikGraph.Serialization.Tests [TestFixture] internal sealed class XmlSerializationTests { - #region Serialization + #region Constants + + [NotNull] + private static readonly string TestNamespace = string.Empty; + + + [NotNull] + private const string IdTag = "id"; + + [NotNull] + private const string GraphTag = "graph"; + + [NotNull] + private const string NodeTag = "node"; + + [NotNull] + private const string EdgeTag = "edge"; + + [NotNull] + private const string SourceTag = "source"; + + [NotNull] + private const string TargetTag = "target"; + + + #region Custom data constants + + [NotNull] + private const string WeightTag = "weight"; + + [NotNull] + private const string TypeTag = "type"; + + [NotNull] + private const string StringDefaultTag = "strDefault"; + + [NotNull] + private const string StringTag = "str"; + + [NotNull] + private const string BoolTag = "bool"; + + [NotNull] + private const string IntTag = "i32"; + + [NotNull] + private const string LongTag = "i64"; + + [NotNull] + private const string FloatTag = "f32"; [NotNull] - private const string GraphNodeName = "family"; + private const string DoubleTag = "f64"; [NotNull] - private const string VertexNodeName = "person"; + private const string AdditionalDataTag = "additional_data"; [NotNull] - private const string EdgeNodeName = "relationship"; + private const string IsTaggedTag = "has_tag"; + + [NotNull] + private const string DoubleValueTag = "double_tag"; + + [NotNull] + private const string StringValueTag = "string_tag"; + + #endregion + + + [NotNull] + private const string FamilyGraphTag = "family"; + + [NotNull] + private const string PersonNodeTag = "person"; + + [NotNull] + private const string RelationEdgeTag = "relationship"; + [NotNull] private const string XmlHeader = ""; + [NotNull] private const string Indent = " "; + + [NotNull] + private const string NullString = ""; + + #endregion + + #region Serialization + #region Test helpers private static void SerializeAndRead( @@ -73,14 +152,14 @@ public void SerializeToXml_Empty() writer, person => person.Id, emptyGraph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, - EdgeNodeName, - ""), + FamilyGraphTag, + PersonNodeTag, + RelationEdgeTag, + TestNamespace), content => { StringAssert.AreEqualIgnoringCase( - $"{XmlHeader}{Environment.NewLine}<{GraphNodeName} />", + $"{XmlHeader}{Environment.NewLine}<{FamilyGraphTag} />", content); }); } @@ -146,10 +225,10 @@ public void SerializeToXml([NotNull] TGraph graph) writer, person => person.Id, graph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, - EdgeNodeName, - ""), + FamilyGraphTag, + PersonNodeTag, + RelationEdgeTag, + TestNamespace), content => CheckXmlGraphSerialization(graph, content)); #region Local function @@ -159,20 +238,20 @@ static void CheckXmlGraphSerialization( [NotNull] string xmlGraph) { var expectedSerializedGraph = new StringBuilder($"{XmlHeader}{Environment.NewLine}"); - expectedSerializedGraph.AppendLine($"<{GraphNodeName}>"); + expectedSerializedGraph.AppendLine($"<{FamilyGraphTag}>"); foreach (Person person in graph.Vertices) { - expectedSerializedGraph.AppendLine($"{Indent}<{VertexNodeName} id=\"{person.Id}\" />"); + expectedSerializedGraph.AppendLine($"{Indent}<{PersonNodeTag} id=\"{person.Id}\" />"); } TaggedEdge[] relations = graph.Edges.ToArray(); for (int i = 0; i < relations.Length; ++i) { - expectedSerializedGraph.AppendLine($"{Indent}<{EdgeNodeName} id=\"{i}\" source=\"{relations[i].Source.Id}\" target=\"{relations[i].Target.Id}\" />"); + expectedSerializedGraph.AppendLine($"{Indent}<{RelationEdgeTag} id=\"{i}\" source=\"{relations[i].Source.Id}\" target=\"{relations[i].Target.Id}\" />"); } - expectedSerializedGraph.Append($""); + expectedSerializedGraph.Append($""); StringAssert.AreEqualIgnoringCase( expectedSerializedGraph.ToString(), @@ -192,10 +271,10 @@ public void SerializationToXml_Throws() null, vertex => vertex.ToString(), graph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, - EdgeNodeName, - "")); + FamilyGraphTag, + PersonNodeTag, + RelationEdgeTag, + TestNamespace)); using (var memory = new MemoryStream()) using (var writer = new StreamWriter(memory)) @@ -206,30 +285,30 @@ public void SerializationToXml_Throws() xmlWriter, vertex => vertex.ToString(), graph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, - EdgeNodeName, - "")); + FamilyGraphTag, + PersonNodeTag, + RelationEdgeTag, + TestNamespace)); Assert.Throws( () => graph.SerializeToXml( xmlWriter, null, graph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, - EdgeNodeName, - "")); + FamilyGraphTag, + PersonNodeTag, + RelationEdgeTag, + TestNamespace)); Assert.Throws( () => graph.SerializeToXml, AdjacencyGraph>>( xmlWriter, vertex => vertex.ToString(), null, - GraphNodeName, - VertexNodeName, - EdgeNodeName, - "")); + FamilyGraphTag, + PersonNodeTag, + RelationEdgeTag, + TestNamespace)); Assert.Throws( () => graph.SerializeToXml( @@ -237,9 +316,9 @@ public void SerializationToXml_Throws() vertex => vertex.ToString(), graph.GetEdgeIdentity(), null, - VertexNodeName, - EdgeNodeName, - "")); + PersonNodeTag, + RelationEdgeTag, + TestNamespace)); Assert.Throws( () => graph.SerializeToXml( @@ -247,47 +326,47 @@ public void SerializationToXml_Throws() vertex => vertex.ToString(), graph.GetEdgeIdentity(), "", - VertexNodeName, - EdgeNodeName, - "")); + PersonNodeTag, + RelationEdgeTag, + TestNamespace)); Assert.Throws( () => graph.SerializeToXml( xmlWriter, vertex => vertex.ToString(), graph.GetEdgeIdentity(), - GraphNodeName, + FamilyGraphTag, null, - EdgeNodeName, - "")); + RelationEdgeTag, + TestNamespace)); Assert.Throws( () => graph.SerializeToXml( xmlWriter, vertex => vertex.ToString(), graph.GetEdgeIdentity(), - GraphNodeName, + FamilyGraphTag, "", - EdgeNodeName, - "")); + RelationEdgeTag, + TestNamespace)); Assert.Throws( () => graph.SerializeToXml( xmlWriter, vertex => vertex.ToString(), graph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, + FamilyGraphTag, + PersonNodeTag, null, - "")); + TestNamespace)); Assert.Throws( () => graph.SerializeToXml( xmlWriter, vertex => vertex.ToString(), graph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, + FamilyGraphTag, + PersonNodeTag, "", "")); @@ -296,9 +375,9 @@ public void SerializationToXml_Throws() xmlWriter, vertex => vertex.ToString(), graph.GetEdgeIdentity(), - GraphNodeName, - VertexNodeName, - EdgeNodeName, + FamilyGraphTag, + PersonNodeTag, + RelationEdgeTag, null)); } // ReSharper restore AssignNullToNotNullAttribute @@ -366,39 +445,39 @@ public void DeserializeFromXml_Document_Empty() // Directed graph AdjacencyGraph> adjacencyGraph = document.DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, TestNamespace), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", ""))); + nav.GetAttribute(SourceTag, TestNamespace), + nav.GetAttribute(TargetTag, TestNamespace))); AssertEmptyGraph(adjacencyGraph); // Directed bidirectional graph BidirectionalGraph> bidirectionalGraph = document.DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new BidirectionalGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, TestNamespace), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", ""))); + nav.GetAttribute(SourceTag, TestNamespace), + nav.GetAttribute(TargetTag, TestNamespace))); AssertEmptyGraph(bidirectionalGraph); // Undirected graph UndirectedGraph> undirectedGraph = document.DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new UndirectedGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, TestNamespace), nav => new TaggedEdge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", ""), - int.Parse(nav.GetAttribute("weight", "")))); + nav.GetAttribute(SourceTag, TestNamespace), + nav.GetAttribute(TargetTag, TestNamespace), + int.Parse(nav.GetAttribute(WeightTag, TestNamespace)))); AssertEmptyGraph(undirectedGraph); } @@ -409,43 +488,43 @@ public void DeserializeFromXml_Document() // Directed graph AdjacencyGraph> adjacencyGraph = document.DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, TestNamespace), nav => new EquatableEdge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", ""))); + nav.GetAttribute(SourceTag, TestNamespace), + nav.GetAttribute(TargetTag, TestNamespace))); AssetTestGraphContent( adjacencyGraph, (v1, v2, _) => new EquatableEdge(v1, v2)); // Directed bidirectional graph BidirectionalGraph> bidirectionalGraph = document.DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new BidirectionalGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, TestNamespace), nav => new EquatableEdge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", ""))); + nav.GetAttribute(SourceTag, TestNamespace), + nav.GetAttribute(TargetTag, TestNamespace))); AssetTestGraphContent( bidirectionalGraph, (v1, v2, _) => new EquatableEdge(v1, v2)); // Undirected graph UndirectedGraph> undirectedGraph = document.DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new UndirectedGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, TestNamespace), nav => new EquatableTaggedEdge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", ""), - int.Parse(nav.GetAttribute("weight", "")))); + nav.GetAttribute(SourceTag, TestNamespace), + nav.GetAttribute(TargetTag, TestNamespace), + int.Parse(nav.GetAttribute(WeightTag, TestNamespace)))); AssetTestGraphContent( undirectedGraph, (v1, v2, weight) => new EquatableTaggedEdge(v1, v2, weight)); @@ -458,125 +537,125 @@ public void DeserializeFromXml_Document_Throws() // ReSharper disable AssignNullToNotNullAttribute Assert.Throws( () => ((XPathDocument) null).DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new EquatableEdge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); var document = new XPathDocument(GetGraphFilePath(TestGraphFileName)); Assert.Throws( () => document.DeserializeFromXml( null, - "node", - "edge", + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml( "", - "node", - "edge", + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml( - "graph", + GraphTag, null, - "edge", + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml( - "graph", + GraphTag, "", - "edge", + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml( - "graph", - "node", + GraphTag, + NodeTag, null, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml( - "graph", - "node", + GraphTag, + NodeTag, "", _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml, AdjacencyGraph>>( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, null, - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml, AdjacencyGraph>>( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), null, nav => new Edge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); Assert.Throws( () => document.DeserializeFromXml, AdjacencyGraph>>( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), null)); // No graph node found Assert.Throws( () => document.DeserializeFromXml( "g", // No node named "g" for the graph - "node", - "edge", + NodeTag, + EdgeTag, _ => new AdjacencyGraph>(), - nav => nav.GetAttribute("id", ""), + nav => nav.GetAttribute(IdTag, ""), nav => new EquatableEdge( - nav.GetAttribute("source", ""), - nav.GetAttribute("target", "")))); + nav.GetAttribute(SourceTag, ""), + nav.GetAttribute(TargetTag, "")))); // ReSharper restore AssignNullToNotNullAttribute // ReSharper restore ReturnValueOfPureMethodIsNotUsed } @@ -587,47 +666,46 @@ public void DeserializeFromXml_Reader_Empty() using (var reader = XmlReader.Create(GetGraphFilePath(EmptyGraphFileName))) { AdjacencyGraph> adjacencyGraph = reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute"))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute"))); AssertEmptyGraph(adjacencyGraph); } using (var reader = XmlReader.Create(GetGraphFilePath(EmptyGraphFileName))) { BidirectionalGraph> bidirectionalGraph = reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new BidirectionalGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute"))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute"))); AssertEmptyGraph(bidirectionalGraph); } using (var reader = XmlReader.Create(GetGraphFilePath(EmptyGraphFileName))) { UndirectedGraph> undirectedGraph = reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new UndirectedGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new TaggedEdge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute"), - int.Parse( - r.GetAttribute("weight") ?? throw new AssertionException("Must have weight attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute"), + int.Parse(r.GetAttribute(WeightTag) ?? throw new AssertionException("Must have weight attribute")))); AssertEmptyGraph(undirectedGraph); } } @@ -638,15 +716,15 @@ public void DeserializeFromXml_Reader() using (var reader = XmlReader.Create(GetGraphFilePath(TestGraphFileName))) { AdjacencyGraph> adjacencyGraph = reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new EquatableEdge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute"))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute"))); AssetTestGraphContent( adjacencyGraph, (v1, v2, _) => new EquatableEdge(v1, v2)); @@ -655,15 +733,15 @@ public void DeserializeFromXml_Reader() using (var reader = XmlReader.Create(GetGraphFilePath(TestGraphFileName))) { BidirectionalGraph> bidirectionalGraph = reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new BidirectionalGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new EquatableEdge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute"))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute"))); AssetTestGraphContent( bidirectionalGraph, (v1, v2, _) => new EquatableEdge(v1, v2)); @@ -672,17 +750,16 @@ public void DeserializeFromXml_Reader() using (var reader = XmlReader.Create(GetGraphFilePath(TestGraphFileName))) { UndirectedGraph> undirectedGraph = reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new UndirectedGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new EquatableTaggedEdge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute"), - int.Parse( - r.GetAttribute("weight") ?? throw new AssertionException("Must have weight attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute"), + int.Parse(r.GetAttribute(WeightTag) ?? throw new AssertionException("Must have weight attribute")))); AssetTestGraphContent( undirectedGraph, (v1, v2, weight) => new EquatableTaggedEdge(v1, v2, weight)); @@ -696,47 +773,47 @@ public void DeserializeFromXml_Reader_Throws() // ReSharper disable AssignNullToNotNullAttribute Assert.Throws( () => ((XmlReader)null).DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); using (var reader = XmlReader.Create(GetGraphFilePath(TestGraphFileName))) { Assert.Throws(() => reader.DeserializeFromXml, AdjacencyGraph>>( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, "", null, - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml, AdjacencyGraph>>( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, "", _ => new AdjacencyGraph>(), null, r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml, AdjacencyGraph>>( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), null)); @@ -744,125 +821,125 @@ public void DeserializeFromXml_Reader_Throws() () => reader.DeserializeFromXml( null, r => r.Name == "vertex", - r => r.Name == "edge", + r => r.Name == EdgeTag, _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws( () => reader.DeserializeFromXml( - r => r.Name == "graph", + r => r.Name == GraphTag, null, - r => r.Name == "edge", + r => r.Name == EdgeTag, _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws( () => reader.DeserializeFromXml( - r => r.Name == "graph", + r => r.Name == GraphTag, r => r.Name == "vertex", null, _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml( null, - "node", - "edge", + NodeTag, + EdgeTag, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml( "", - "node", - "edge", + NodeTag, + EdgeTag, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml( - "graph", + GraphTag, null, - "edge", + EdgeTag, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml( - "graph", + GraphTag, "", - "edge", + EdgeTag, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml( - "graph", - "node", + GraphTag, + NodeTag, null, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml( - "graph", - "node", + GraphTag, + NodeTag, "", "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); Assert.Throws(() => reader.DeserializeFromXml( - "graph", - "node", - "edge", + GraphTag, + NodeTag, + EdgeTag, null, _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); // No graph node found Assert.Throws(() => reader.DeserializeFromXml( "g", // No node named "g" for the graph - "node", - "edge", + NodeTag, + EdgeTag, "", _ => new AdjacencyGraph>(), - r => r.GetAttribute("id"), + r => r.GetAttribute(IdTag), r => new Edge( - r.GetAttribute("source") ?? throw new AssertionException("Must have source attribute"), - r.GetAttribute("target") ?? throw new AssertionException("Must have target attribute")))); + r.GetAttribute(SourceTag) ?? throw new AssertionException("Must have source attribute"), + r.GetAttribute(TargetTag) ?? throw new AssertionException("Must have target attribute")))); } // ReSharper restore AssignNullToNotNullAttribute // ReSharper restore ReturnValueOfPureMethodIsNotUsed @@ -875,20 +952,268 @@ public void DeserializeFromXml_Reader_Throws() #region Test Helpers [Pure] - private static int DeserializeVertex([NotNull] XmlReader reader) + [NotNull] + private static string GetSerializableString([CanBeNull] string str) + { + return str ?? NullString; + } + + private static void SerializeEdge_Simple([NotNull] XmlWriter writer, [NotNull] TInEdge edge) + where TInEdge : IEdge, IEquatable + { + // Serialize only relevant stuff for the test + switch (edge) + { + case EquatableTaggedEdge edgeDoubleTag: + writer.WriteAttributeString(IsTaggedTag, TestNamespace, bool.TrueString); + writer.WriteAttributeString(DoubleValueTag, TestNamespace, edgeDoubleTag.Tag.ToString(CultureInfo.InvariantCulture)); + break; + + case EquatableTaggedEdge edgeStringTag: + writer.WriteAttributeString(IsTaggedTag, TestNamespace, bool.TrueString); + writer.WriteAttributeString(StringValueTag, TestNamespace, GetSerializableString(edgeStringTag.Tag)); + break; + + default: + writer.WriteAttributeString(IsTaggedTag, TestNamespace, bool.FalseString); + break; + } + } + + [Pure] + private static int DeserializeVertex_Simple([NotNull] XmlReader reader) + { + return int.Parse(reader.GetAttribute(IdTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize vertex.")); + } + + [Pure] + [NotNull] + private static EquatableEdge DeserializeEdge_Simple([NotNull] XmlReader reader) + { + int source = int.Parse(reader.GetAttribute(SourceTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge source.")); + int target = int.Parse(reader.GetAttribute(TargetTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge target.")); + + bool hasTag = bool.Parse(reader.GetAttribute(IsTaggedTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge tag info.")); + if (hasTag) + { + string attribute = reader.GetAttribute(DoubleValueTag, TestNamespace); + if (attribute is null) + { + attribute = reader.GetAttribute(StringValueTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize vertex tag."); + return new EquatableTaggedEdge(source, target, GetString(attribute)); + } + + return new EquatableTaggedEdge( + source, + target, + double.Parse(attribute, CultureInfo.InvariantCulture)); + } + + return new EquatableEdge(source, target); + + + #region Local function + + string GetString(string readStr) + { + return NullString.Equals(readStr, StringComparison.Ordinal) ? null : readStr; + } + + #endregion + } + + [Pure] + private static SEquatableEdge DeserializeSEdge_Simple([NotNull] XmlReader reader) + { + return new SEquatableEdge( + int.Parse(reader.GetAttribute(SourceTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge source.")), + int.Parse(reader.GetAttribute(TargetTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge target."))); + } + + private static void SerializeVertex_Complex([NotNull] XmlWriter writer, [NotNull] EquatableTestVertex vertex) + { + // Serialize only relevant stuff for the test + Type vertexType = vertex.GetType(); + writer.WriteAttributeString(TypeTag, TestNamespace, TypeToSerializableType(vertexType)); + + writer.WriteAttributeString(StringDefaultTag, TestNamespace, GetSerializableString(vertex.StringDefault)); + writer.WriteAttributeString(StringTag, TestNamespace, GetSerializableString(vertex.String)); + writer.WriteAttributeString(BoolTag, TestNamespace, vertex.Bool.ToString()); + writer.WriteAttributeString(IntTag, TestNamespace, vertex.Int.ToString()); + writer.WriteAttributeString(LongTag, TestNamespace, vertex.Long.ToString()); + writer.WriteAttributeString(FloatTag, TestNamespace, vertex.Float.ToString(CultureInfo.InvariantCulture)); + writer.WriteAttributeString(DoubleTag, TestNamespace, vertex.Double.ToString(CultureInfo.InvariantCulture)); + + if (vertex is EquatableAdditionalDataTestVertex vertexWithData) + { + writer.WriteAttributeString(AdditionalDataTag, TestNamespace, vertexWithData.Data.ToString(CultureInfo.InvariantCulture)); + } + } + + private static void SerializeEdge_Complex([NotNull] XmlWriter writer, [NotNull] TInEdge edge) + where TInEdge : IEdge, IEquatable + { + // Serialize only relevant stuff for the test + IEdge edgeToCheck = edge; + if (edge is SReversedEdge reversedEdge) + { + edgeToCheck = reversedEdge.OriginalEdge; + } + + Type edgeType = edgeToCheck.GetType(); + writer.WriteAttributeString(TypeTag, TestNamespace, TypeToSerializableType(edgeType)); + + if (edgeToCheck is EquatableTestEdge edgeToSerialize) + { + writer.WriteAttributeString(StringTag, TestNamespace, GetSerializableString(edgeToSerialize.String)); + writer.WriteAttributeString(BoolTag, TestNamespace, edgeToSerialize.Bool.ToString()); + writer.WriteAttributeString(IntTag, TestNamespace, edgeToSerialize.Int.ToString()); + writer.WriteAttributeString(LongTag, TestNamespace, edgeToSerialize.Long.ToString()); + writer.WriteAttributeString(FloatTag, TestNamespace, edgeToSerialize.Float.ToString(CultureInfo.InvariantCulture)); + writer.WriteAttributeString(DoubleTag, TestNamespace, edgeToSerialize.Double.ToString(CultureInfo.InvariantCulture)); + } + + if (edgeToCheck is EquatableAdditionalDataTestEdge edgeToSerializeWithData) + { + writer.WriteAttributeString(AdditionalDataTag, TestNamespace, edgeToSerializeWithData.Data.ToString(CultureInfo.InvariantCulture)); + } + } + + [Pure] + [NotNull] + private static EquatableTestVertex DeserializeVertex_Complex([NotNull] XmlReader reader) + { + string id = reader.GetAttribute(IdTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize vertex id."); + var type = Type.GetType(reader.GetAttribute(TypeTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize vertex type.")); + + EquatableTestVertex vertex = type == typeof(EquatableAdditionalDataTestVertex) + ? new EquatableAdditionalDataTestVertex( + id, + double.Parse(reader.GetAttribute(AdditionalDataTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize vertex data."))) + : new EquatableTestVertex(id); + + return AssignData(vertex); + + #region Local function + + EquatableTestVertex AssignData(EquatableTestVertex v) + { + v.StringDefault = GetString(StringDefaultTag); + v.String = GetString(StringTag); + v.Bool = bool.Parse(reader.GetAttribute(BoolTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize vertex \"{BoolTag}\" tag.")); + v.Int = int.Parse(reader.GetAttribute(IntTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize vertex \"{IntTag}\" tag.")); + v.Long = long.Parse(reader.GetAttribute(LongTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize vertex \"{LongTag}\" tag.")); + v.Float = float.Parse( + reader.GetAttribute(FloatTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize vertex \"{FloatTag}\" tag."), + CultureInfo.InvariantCulture); + v.Double = double.Parse( + reader.GetAttribute(DoubleTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize vertex \"{DoubleTag}\" tag."), + CultureInfo.InvariantCulture); + + return v; + + #region Local function + + string GetString(string tag) + { + string readStr = reader.GetAttribute(tag, TestNamespace) + ?? throw new AssertionException($"Unable to deserialize vertex \"{tag}\" tag."); + return NullString.Equals(readStr, StringComparison.Ordinal) ? null : readStr; + } + + #endregion + } + + #endregion + } + + [Pure] + [NotNull] + private static EquatableTestVertex DeserializeVertex_Complex([NotNull] XmlReader reader, [NotNull] IDictionary verticesCache) + { + EquatableTestVertex vertex = DeserializeVertex_Complex(reader); + verticesCache[VertexIdentity_Complex(vertex)] = vertex; + return vertex; + } + + [Pure] + [NotNull] + private static EquatableTestEdge DeserializeEdge_Complex([NotNull] XmlReader reader, [NotNull] IDictionary verticesCache) + { + string id = reader.GetAttribute(IdTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge id."); + + string sourceId = reader.GetAttribute(SourceTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge source id."); + string targetId = reader.GetAttribute(TargetTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge target id."); + EquatableTestVertex source = verticesCache[sourceId]; + EquatableTestVertex target = verticesCache[targetId]; + + var type = Type.GetType(reader.GetAttribute(TypeTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge type.")); + + EquatableTestEdge edge = type == typeof(EquatableAdditionalDataTestEdge) + ? new EquatableAdditionalDataTestEdge( + source, + target, + id, + double.Parse(reader.GetAttribute(AdditionalDataTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge data."), CultureInfo.InvariantCulture)) + : new EquatableTestEdge(source, target, id); + + return AssignData(edge); + + #region Local function + + EquatableTestEdge AssignData(EquatableTestEdge e) + { + e.String = GetString(StringTag); + e.Bool = bool.Parse(reader.GetAttribute(BoolTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize edge \"{BoolTag}\" tag.")); + e.Int = int.Parse(reader.GetAttribute(IntTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize edge \"{IntTag}\" tag.")); + e.Long = long.Parse(reader.GetAttribute(LongTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize edge \"{LongTag}\" tag.")); + e.Float = float.Parse( + reader.GetAttribute(FloatTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize edge \"{FloatTag}\" tag."), + CultureInfo.InvariantCulture); + e.Double = double.Parse( + reader.GetAttribute(DoubleTag, TestNamespace) ?? throw new AssertionException($"Unable to deserialize edge \"{DoubleTag}\" tag."), + CultureInfo.InvariantCulture); + + return e; + + #region Local function + + string GetString(string tag) + { + string readStr = reader.GetAttribute(tag, TestNamespace) + ?? throw new AssertionException($"Unable to deserialize edge \"{tag}\" tag."); + return NullString.Equals(readStr, StringComparison.Ordinal) ? null : readStr; + } + + #endregion + } + + #endregion + } + + [Pure] + private static SEquatableEdge DeserializeSEdge_Complex([NotNull] XmlReader reader, [NotNull] IDictionary verticesCache) { - return int.Parse(reader.GetAttribute("id", "") ?? throw new AssertionException("Unable to deserialize vertex.")); + string sourceId = reader.GetAttribute(SourceTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge source id."); + string targetId = reader.GetAttribute(TargetTag, TestNamespace) ?? throw new AssertionException("Unable to deserialize edge target id."); + EquatableTestVertex source = verticesCache[sourceId]; + EquatableTestVertex target = verticesCache[targetId]; + + return new SEquatableEdge(source, target); } [Pure] [NotNull] - private static TOutGraph SerializeDeserialize( + private static TOutGraph SerializeDeserialize( [NotNull] TInGraph graph, + [NotNull, InstantHandle] VertexIdentity vertexIdentity, + [CanBeNull, InstantHandle] Action vertexAttributes, + [CanBeNull, InstantHandle] Action edgeAttributes, [NotNull, InstantHandle] Func deserialize) - where TInEdge : IEdge, IEquatable - where TOutEdge : IEdge, IEquatable - where TInGraph : IEdgeListGraph - where TOutGraph : IEdgeListGraph + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph { Assert.IsNotNull(graph); @@ -901,12 +1226,15 @@ private static TOutGraph SerializeDeserialize vertex.ToString(), + vertexIdentity, graph.GetEdgeIdentity(), - "graph", - "node", - "edge", - ""); + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, + null, + vertexAttributes, + edgeAttributes); } memory.Position = 0; @@ -924,128 +1252,282 @@ private static TOutGraph SerializeDeserialize([NotNull] TInGraph graph) + private static TOutGraph SerializeDeserialize_Simple( + [NotNull] TInGraph graph, + [NotNull, InstantHandle] Func deserialize) + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph + { + return SerializeDeserialize( + graph, + VertexIdentity_Simple, + null, + SerializeEdge_Simple, + deserialize); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Complex( + [NotNull] TInGraph graph, + [NotNull, InstantHandle] Func deserialize) + where TInEdge : IEdge, IEquatable + where TOutEdge : IEdge, IEquatable + where TInGraph : IEdgeListGraph + where TOutGraph : IEdgeListGraph + { + return SerializeDeserialize( + graph, + VertexIdentity_Complex, + SerializeVertex_Complex, + SerializeEdge_Complex, + deserialize); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Simple([NotNull] TInGraph graph) where TInGraph : IEdgeListGraph> where TOutGraph : class, IMutableVertexAndEdgeSet>, new() { - return SerializeDeserialize, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + return SerializeDeserialize_Simple, EquatableEdge, TInGraph, TOutGraph>(graph, reader => reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, + _ => new TOutGraph(), + DeserializeVertex_Simple, + DeserializeEdge_Simple)); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Complex([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph + where TOutGraph : class, IMutableVertexAndEdgeSet, new() + { + var verticesCache = new Dictionary(); + return SerializeDeserialize_Complex(graph, reader => + reader.DeserializeFromXml( + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new TOutGraph(), - DeserializeVertex, - nav => new EquatableEdge( - int.Parse(nav.GetAttribute("source", "") ?? throw new AssertionException("Unable to deserialize edge source.")), - int.Parse(nav.GetAttribute("target", "") ?? throw new AssertionException("Unable to deserialize edge target."))))); + r => DeserializeVertex_Complex(r, verticesCache), + r => DeserializeEdge_Complex(r, verticesCache))); } [Pure] [NotNull] - private static TOutGraph SerializeDeserialize_SEdge([NotNull] TInGraph graph) + private static TOutGraph SerializeDeserialize_SEdge_Simple([NotNull] TInGraph graph) where TInGraph : IEdgeListGraph> where TOutGraph : class, IMutableVertexAndEdgeSet>, new() { - return SerializeDeserialize, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => + return SerializeDeserialize_Simple, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new TOutGraph(), - DeserializeVertex, - nav => new SEquatableEdge( - int.Parse(nav.GetAttribute("source", "") ?? throw new AssertionException("Unable to deserialize edge source.")), - int.Parse(nav.GetAttribute("target", "") ?? throw new AssertionException("Unable to deserialize edge target."))))); + DeserializeVertex_Simple, + DeserializeSEdge_Simple)); } [Pure] [NotNull] - private static TOutGraph SerializeDeserialize_Reversed([NotNull] TInGraph graph) + private static TOutGraph SerializeDeserialize_SEdge_Complex([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet>, new() + { + var verticesCache = new Dictionary(); + return SerializeDeserialize_Complex, SEquatableEdge, TInGraph, TOutGraph>(graph, reader => + reader.DeserializeFromXml( + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, + _ => new TOutGraph(), + r => DeserializeVertex_Complex(r, verticesCache), + r => DeserializeSEdge_Complex(r, verticesCache))); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Reversed_Simple([NotNull] TInGraph graph) where TInGraph : IEdgeListGraph>> where TOutGraph : class, IMutableVertexAndEdgeSet>, new() { - return SerializeDeserialize>, EquatableEdge, TInGraph, TOutGraph>(graph, reader => + return SerializeDeserialize_Simple>, EquatableEdge, TInGraph, TOutGraph>(graph, reader => reader.DeserializeFromXml( - "graph", - "node", - "edge", - "", + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, + _ => new TOutGraph(), + DeserializeVertex_Simple, + DeserializeEdge_Simple)); + } + + [Pure] + [NotNull] + private static TOutGraph SerializeDeserialize_Reversed_Complex([NotNull] TInGraph graph) + where TInGraph : IEdgeListGraph> + where TOutGraph : class, IMutableVertexAndEdgeSet, new() + { + var verticesCache = new Dictionary(); + return SerializeDeserialize_Complex, EquatableTestEdge, TInGraph, TOutGraph>(graph, reader => + reader.DeserializeFromXml( + GraphTag, + NodeTag, + EdgeTag, + TestNamespace, _ => new TOutGraph(), - DeserializeVertex, - nav => new EquatableEdge( - int.Parse(nav.GetAttribute("source", "") ?? throw new AssertionException("Unable to deserialize edge source.")), - int.Parse(nav.GetAttribute("target", "") ?? throw new AssertionException("Unable to deserialize edge target."))))); + r => DeserializeVertex_Complex(r, verticesCache), + r => DeserializeEdge_Complex(r, verticesCache))); } #endregion [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] - public void XmlSerialization_AdjacencyGraph([NotNull] AdjacencyGraph> graph) + public void XmlSerialization_AdjacencyGraph_Simple([NotNull] AdjacencyGraph> graph) { AdjacencyGraph> deserializedGraph1 = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); var arrayGraph = new ArrayAdjacencyGraph>(graph); AdjacencyGraph> deserializedGraph2 = - SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphComplexTestCases))] + public void XmlSerialization_AdjacencyGraph_Complex([NotNull] AdjacencyGraph graph) + { + AdjacencyGraph deserializedGraph1 = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayAdjacencyGraph(graph); + AdjacencyGraph deserializedGraph2 = + SerializeDeserialize_Complex, AdjacencyGraph>(arrayGraph); Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphTestCases))] - public void XmlSerialization_AdapterGraph([NotNull] AdjacencyGraph> graph) + public void XmlSerialization_AdapterGraph_Simple([NotNull] AdjacencyGraph> graph) { var bidirectionalAdapterGraph = new BidirectionalAdapterGraph>(graph); AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(bidirectionalAdapterGraph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(bidirectionalAdapterGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationAdjacencyGraphComplexTestCases))] + public void XmlSerialization_AdapterGraph_Complex([NotNull] AdjacencyGraph graph) + { + var bidirectionalAdapterGraph = new BidirectionalAdapterGraph(graph); + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(bidirectionalAdapterGraph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphTestCases))] - public void XmlSerialization_ClusteredGraph([NotNull] ClusteredAdjacencyGraph> graph) + public void XmlSerialization_ClusteredGraph_Simple([NotNull] ClusteredAdjacencyGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationClusteredAdjacencyGraphComplexTestCases))] + public void XmlSerialization_ClusteredGraph_Complex([NotNull] ClusteredAdjacencyGraph graph) + { + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphTestCases))] - public void XmlSerialization_CompressedGraph([NotNull] CompressedSparseRowGraph graph) + public void XmlSerialization_CompressedGraph_Simple([NotNull] CompressedSparseRowGraph graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize_SEdge, AdjacencyGraph>>(graph); + SerializeDeserialize_SEdge_Simple, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationCompressedGraphComplexTestCases))] + public void XmlSerialization_CompressedGraph_Complex([NotNull] CompressedSparseRowGraph graph) + { + AdjacencyGraph> deserializedGraph = + SerializeDeserialize_SEdge_Complex, AdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphTestCases))] - public void XmlSerialization_BidirectionalGraph([NotNull] BidirectionalGraph> graph) + public void XmlSerialization_BidirectionalGraph_Simple([NotNull] BidirectionalGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); var arrayGraph = new ArrayBidirectionalGraph>(graph); AdjacencyGraph> deserializedGraph2 = - SerializeDeserialize>, AdjacencyGraph>>(arrayGraph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(arrayGraph); Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); var reversedGraph = new ReversedBidirectionalGraph>(graph); BidirectionalGraph> deserializedGraph3 = - SerializeDeserialize_Reversed>, BidirectionalGraph>>(reversedGraph); + SerializeDeserialize_Reversed_Simple>, BidirectionalGraph>>(reversedGraph); Assert.IsTrue( EquateGraphs.Equate( graph, deserializedGraph3, EqualityComparer.Default, LambdaEqualityComparer>.Create( - (edge1, edge2) => Equals(edge1.Source, edge2.Target) && Equals(edge1.Target, edge2.Source), + (edge1, edge2) => Equals(edge1.Source, edge2.Target) + && Equals(edge1.Target, edge2.Source) + && edge1.GetType() == edge2.GetType(), edge => edge.GetHashCode()))); var undirectedBidirectionalGraph = new UndirectedBidirectionalGraph>(graph); UndirectedGraph> deserializedGraph4 = - SerializeDeserialize>, UndirectedGraph>>(undirectedBidirectionalGraph); + SerializeDeserialize_Simple>, UndirectedGraph>>(undirectedBidirectionalGraph); + Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationBidirectionalGraphComplexTestCases))] + public void XmlSerialization_BidirectionalGraph_Complex([NotNull] BidirectionalGraph graph) + { + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + + var arrayGraph = new ArrayBidirectionalGraph(graph); + AdjacencyGraph deserializedGraph2 = + SerializeDeserialize_Complex, AdjacencyGraph>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(arrayGraph, deserializedGraph2)); + + var reversedGraph = new ReversedBidirectionalGraph(graph); + BidirectionalGraph deserializedGraph3 = + SerializeDeserialize_Reversed_Complex, BidirectionalGraph>(reversedGraph); + Assert.IsTrue( + EquateGraphs.Equate( + graph, + deserializedGraph3, + EqualityComparer.Default, + LambdaEqualityComparer.Create( + (edge1, edge2) => Equals(edge1.Source, edge2.Target) && Equals(edge1.Target, edge2.Source) && edge1.DataContentEquals(edge2), + edge => edge.GetHashCode()))); + + var undirectedBidirectionalGraph = new UndirectedBidirectionalGraph(graph); + UndirectedGraph deserializedGraph4 = + SerializeDeserialize_Complex, UndirectedGraph>(undirectedBidirectionalGraph); Assert.IsTrue(EquateGraphs.Equate(undirectedBidirectionalGraph, deserializedGraph4)); } @@ -1053,28 +1535,56 @@ public void XmlSerialization_BidirectionalGraph([NotNull] BidirectionalGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); - Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); + Assert.IsTrue( + EquateGraphs.Equate( + graph, + deserializedGraph, + EqualityComparer.Default, + LambdaEqualityComparer>.Create( + (edge1, edge2) => EqualityComparer>.Default.Equals(edge1, edge2) && edge1.GetType() == edge2.GetType(), + edge => edge.GetHashCode()))); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphTestCases))] - public void XmlSerialization_UndirectedGraph([NotNull] UndirectedGraph> graph) + public void XmlSerialization_UndirectedGraph_Simple([NotNull] UndirectedGraph> graph) { UndirectedGraph> deserializedGraph1 = - SerializeDeserialize>, UndirectedGraph>>(graph); + SerializeDeserialize_Simple>, UndirectedGraph>>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); var arrayGraph = new ArrayUndirectedGraph>(graph); UndirectedGraph> deserializedGraph2 = - SerializeDeserialize>, UndirectedGraph>>(arrayGraph); + SerializeDeserialize_Simple>, UndirectedGraph>>(arrayGraph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph2)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationUndirectedGraphComplexTestCases))] + public void XmlSerialization_UndirectedGraph_Complex([NotNull] UndirectedGraph graph) + { + UndirectedGraph deserializedGraph1 = + SerializeDeserialize_Complex, UndirectedGraph>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph1)); + + var arrayGraph = new ArrayUndirectedGraph(graph); + UndirectedGraph deserializedGraph2 = + SerializeDeserialize_Complex, UndirectedGraph>(arrayGraph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph2)); } [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphTestCases))] - public void XmlSerialization_EdgeListGraph([NotNull] EdgeListGraph> graph) + public void XmlSerialization_EdgeListGraph_Simple([NotNull] EdgeListGraph> graph) { AdjacencyGraph> deserializedGraph = - SerializeDeserialize>, AdjacencyGraph>>(graph); + SerializeDeserialize_Simple>, AdjacencyGraph>>(graph); + Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); + } + + [TestCaseSource(typeof(SerializationTestCaseSources), nameof(SerializationEdgeListGraphComplexTestCases))] + public void XmlSerialization_EdgeListGraph_Complex([NotNull] EdgeListGraph graph) + { + AdjacencyGraph deserializedGraph = + SerializeDeserialize_Complex, AdjacencyGraph>(graph); Assert.IsTrue(EquateGraphs.Equate(graph, deserializedGraph)); } From 14f91dc44fca11043912a929497998c29aba1758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Tue, 28 Jun 2022 00:17:25 +0200 Subject: [PATCH 36/39] Minor issues fixes in tests. --- tests/QuikGraph.Data.Tests/DataRelationEdgeTests.cs | 2 +- tests/QuikGraph.Graphviz.Tests/Dot/GraphvizColorTests.cs | 4 +++- .../Algorithms/Condensation/CondensededEdgeTests.cs | 4 ++-- .../Algorithms/Condensation/MergedEdgeTests.cs | 4 ++-- tests/QuikGraph.Tests/Algorithms/TSP/TaskPriorityTests.cs | 4 ++-- tests/QuikGraph.Tests/Structures/Edges/EdgeTests.cs | 4 ++-- tests/QuikGraph.Tests/Structures/Edges/EquatableEdgeTests.cs | 4 ++-- .../Structures/Edges/EquatableTaggedEdgeTests.cs | 2 +- .../Structures/Edges/EquatableTermEdgeTests.cs | 4 ++-- .../Structures/Edges/EquatableUndirectedEdgeTests.cs | 4 ++-- tests/QuikGraph.Tests/Structures/Edges/SEdgeTests.cs | 4 ++-- tests/QuikGraph.Tests/Structures/Edges/SEquatableEdgeTests.cs | 4 ++-- .../Structures/Edges/SEquatableTaggedEdgeTests.cs | 2 +- tests/QuikGraph.Tests/Structures/Edges/SReversedEdgeTests.cs | 4 ++-- tests/QuikGraph.Tests/Structures/Edges/STaggedEdgeTests.cs | 2 +- .../Structures/Edges/STaggedUndirectedEdgeTests.cs | 2 +- .../QuikGraph.Tests/Structures/Edges/SUndirectedEdgeTests.cs | 4 ++-- tests/QuikGraph.Tests/Structures/Edges/TaggedEdgeTests.cs | 2 +- .../Structures/Edges/TaggedUndirectedEdgeTests.cs | 2 +- tests/QuikGraph.Tests/Structures/Edges/TermEdgeTests.cs | 4 ++-- tests/QuikGraph.Tests/Structures/Edges/UndirectedEdgeTests.cs | 4 ++-- 21 files changed, 36 insertions(+), 34 deletions(-) diff --git a/tests/QuikGraph.Data.Tests/DataRelationEdgeTests.cs b/tests/QuikGraph.Data.Tests/DataRelationEdgeTests.cs index 9e3ecc1e0..5831be359 100644 --- a/tests/QuikGraph.Data.Tests/DataRelationEdgeTests.cs +++ b/tests/QuikGraph.Data.Tests/DataRelationEdgeTests.cs @@ -79,7 +79,7 @@ public void Equals() Assert.IsFalse(relation1.Equals(relation3)); Assert.IsFalse(relation3.Equals(relation1)); - Assert.AreNotEqual(relation1, null); + Assert.AreNotEqual(null, relation1); Assert.IsFalse(relation1.Equals(null)); #region Local function diff --git a/tests/QuikGraph.Graphviz.Tests/Dot/GraphvizColorTests.cs b/tests/QuikGraph.Graphviz.Tests/Dot/GraphvizColorTests.cs index d21b7560b..9a788266d 100644 --- a/tests/QuikGraph.Graphviz.Tests/Dot/GraphvizColorTests.cs +++ b/tests/QuikGraph.Graphviz.Tests/Dot/GraphvizColorTests.cs @@ -85,7 +85,9 @@ public void Equals() Assert.IsTrue(color1 != color6); Assert.AreNotEqual(color1, color6); - Assert.AreNotEqual(color1, null); + Assert.AreNotEqual(null, color1); + Assert.IsFalse(color1.Equals(null)); + Assert.AreNotEqual(new TestClass(), color1); Assert.AreNotEqual(color1, new TestClass()); } diff --git a/tests/QuikGraph.Tests/Algorithms/Condensation/CondensededEdgeTests.cs b/tests/QuikGraph.Tests/Algorithms/Condensation/CondensededEdgeTests.cs index d824b8e3b..79a8b458c 100644 --- a/tests/QuikGraph.Tests/Algorithms/Condensation/CondensededEdgeTests.cs +++ b/tests/QuikGraph.Tests/Algorithms/Condensation/CondensededEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; using QuikGraph.Algorithms.Condensation; using QuikGraph.Tests.Structures; @@ -99,7 +99,7 @@ public void Equals() Assert.AreNotEqual(edge1, edge3); Assert.AreNotEqual(edge1, edge4); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); } } } \ No newline at end of file diff --git a/tests/QuikGraph.Tests/Algorithms/Condensation/MergedEdgeTests.cs b/tests/QuikGraph.Tests/Algorithms/Condensation/MergedEdgeTests.cs index 8608e0a7e..096a27a5b 100644 --- a/tests/QuikGraph.Tests/Algorithms/Condensation/MergedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Algorithms/Condensation/MergedEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; using QuikGraph.Algorithms.Condensation; using QuikGraph.Tests.Structures; @@ -119,7 +119,7 @@ public void Equals() Assert.AreNotEqual(edge1, edge3); Assert.AreNotEqual(edge1, edge4); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); } [Test] diff --git a/tests/QuikGraph.Tests/Algorithms/TSP/TaskPriorityTests.cs b/tests/QuikGraph.Tests/Algorithms/TSP/TaskPriorityTests.cs index aac47b712..fd575bdd4 100644 --- a/tests/QuikGraph.Tests/Algorithms/TSP/TaskPriorityTests.cs +++ b/tests/QuikGraph.Tests/Algorithms/TSP/TaskPriorityTests.cs @@ -1,4 +1,4 @@ -using NUnit.Framework; +using NUnit.Framework; using QuikGraph.Algorithms.TSP; namespace QuikGraph.Tests.Algorithms.TSP @@ -50,7 +50,7 @@ public void Equals() Assert.IsTrue(priority1 != priority5); Assert.IsTrue(priority5 != priority1); - Assert.AreNotEqual(priority1, null); + Assert.AreNotEqual(null, priority1); Assert.IsFalse(priority1.Equals(null)); Assert.IsFalse(priority1 == null); Assert.IsFalse(null == priority1); diff --git a/tests/QuikGraph.Tests/Structures/Edges/EdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/EdgeTests.cs index 8c63f7ca7..f0ae29fc2 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/EdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/EdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -56,7 +56,7 @@ public void Equals() Assert.IsFalse(edge1.Equals(edge2)); Assert.IsFalse(edge2.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/EquatableEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/EquatableEdgeTests.cs index c89dfcded..e417bbb82 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/EquatableEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/EquatableEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -58,7 +58,7 @@ public void Equals() Assert.IsFalse(edge1.Equals(edge3)); Assert.IsFalse(edge3.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/EquatableTaggedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/EquatableTaggedEdgeTests.cs index 0bf77f39c..8fd15a60d 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/EquatableTaggedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/EquatableTaggedEdgeTests.cs @@ -73,7 +73,7 @@ public void Equals() Assert.IsFalse(edge4.Equals(edge6)); Assert.IsFalse(edge6.Equals(edge4)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/EquatableTermEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/EquatableTermEdgeTests.cs index 31d4d7033..732154d8c 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/EquatableTermEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/EquatableTermEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -99,7 +99,7 @@ public void Equals() Assert.IsTrue(edge5.Equals(edge6)); Assert.IsTrue(edge6.Equals(edge5)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/EquatableUndirectedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/EquatableUndirectedEdgeTests.cs index 80310df8b..53a01dc56 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/EquatableUndirectedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/EquatableUndirectedEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -60,7 +60,7 @@ public void Equals() Assert.IsTrue(edge1.Equals(edge2)); Assert.IsTrue(edge2.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/SEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/SEdgeTests.cs index 92bd2d5a3..82d54f6de 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/SEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/SEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -77,7 +77,7 @@ public void Equals() Assert.IsFalse(edge3.Equals(edge5)); Assert.IsFalse(edge5.Equals(edge3)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/SEquatableEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/SEquatableEdgeTests.cs index 5e891165b..7ed62d2ca 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/SEquatableEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/SEquatableEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -58,7 +58,7 @@ public void Equals() Assert.IsFalse(edge1.Equals(edge3)); Assert.IsFalse(edge3.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/SEquatableTaggedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/SEquatableTaggedEdgeTests.cs index a90611e4f..21b892ea2 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/SEquatableTaggedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/SEquatableTaggedEdgeTests.cs @@ -109,7 +109,7 @@ public void Equals() Assert.IsTrue(edge6.Equals(edge8)); // Tag is not taken into account for equality Assert.IsTrue(edge8.Equals(edge6)); // Tag is not taken into account for equality - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/SReversedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/SReversedEdgeTests.cs index ec17d8454..6e05b8df6 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/SReversedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/SReversedEdgeTests.cs @@ -82,7 +82,7 @@ public void Equals() Assert.IsFalse(edge1.Equals(edge4)); Assert.IsFalse(edge4.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } @@ -110,8 +110,8 @@ public void Equals2() Assert.IsTrue(edge1.Equals((object)edge2)); Assert.AreNotEqual(edge1, edge3); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); - Assert.AreNotEqual(edge1, null); } [Test] diff --git a/tests/QuikGraph.Tests/Structures/Edges/STaggedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/STaggedEdgeTests.cs index 34ddf24a7..91d52547f 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/STaggedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/STaggedEdgeTests.cs @@ -102,7 +102,7 @@ public void Equals() Assert.IsFalse(edge6.Equals(edge8)); Assert.IsFalse(edge8.Equals(edge6)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/STaggedUndirectedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/STaggedUndirectedEdgeTests.cs index b6f40ea23..80e85a1fb 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/STaggedUndirectedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/STaggedUndirectedEdgeTests.cs @@ -105,7 +105,7 @@ public void Equals() Assert.IsFalse(edge6.Equals(edge8)); Assert.IsFalse(edge8.Equals(edge6)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/SUndirectedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/SUndirectedEdgeTests.cs index fd230e15d..85484af86 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/SUndirectedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/SUndirectedEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -77,7 +77,7 @@ public void Equals() Assert.IsFalse(edge3.Equals(edge5)); Assert.IsFalse(edge5.Equals(edge3)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/TaggedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/TaggedEdgeTests.cs index 2ee46a0da..905bce409 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/TaggedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/TaggedEdgeTests.cs @@ -68,7 +68,7 @@ public void Equals() Assert.IsFalse(edge1.Equals(edge4)); Assert.IsFalse(edge4.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/TaggedUndirectedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/TaggedUndirectedEdgeTests.cs index b446f3331..5ababf8d7 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/TaggedUndirectedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/TaggedUndirectedEdgeTests.cs @@ -77,7 +77,7 @@ public void Equals() Assert.IsFalse(edge1.Equals(edge4)); Assert.IsFalse(edge4.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/TermEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/TermEdgeTests.cs index 157dc81a4..c251536a9 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/TermEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/TermEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -94,7 +94,7 @@ public void Equals() Assert.IsFalse(edge5.Equals(edge6)); Assert.IsFalse(edge6.Equals(edge5)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } diff --git a/tests/QuikGraph.Tests/Structures/Edges/UndirectedEdgeTests.cs b/tests/QuikGraph.Tests/Structures/Edges/UndirectedEdgeTests.cs index be6175792..cef15d3b1 100644 --- a/tests/QuikGraph.Tests/Structures/Edges/UndirectedEdgeTests.cs +++ b/tests/QuikGraph.Tests/Structures/Edges/UndirectedEdgeTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using NUnit.Framework; namespace QuikGraph.Tests.Structures @@ -59,7 +59,7 @@ public void Equals() Assert.IsFalse(edge1.Equals(edge2)); Assert.IsFalse(edge2.Equals(edge1)); - Assert.AreNotEqual(edge1, null); + Assert.AreNotEqual(null, edge1); Assert.IsFalse(edge1.Equals(null)); } From 10b4ceaac5604799a433aff36ad2a85ac6379499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Sun, 3 Jul 2022 21:01:07 +0200 Subject: [PATCH 37/39] Comment fix. --- src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs b/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs index 8380ab8de..d0d08a75e 100644 --- a/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs +++ b/src/QuikGraph.Graphviz/Extensions/GraphvizExtensions.cs @@ -104,7 +104,7 @@ public static string ToSvg( } /// - /// Performs a layout from DOT to an SVG (Scalable Vector Graphics) file + /// Performs a layout from DOT to a SVG (Scalable Vector Graphics) file /// by calling Agl through the https://rise4fun.com/ REST services. /// /// The dot graph From 19a63f057db49a2b179df22f0e61d347cd8da822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Tue, 12 Oct 2021 00:37:16 +0200 Subject: [PATCH 38/39] Add .NET 4.6.1 target that will be the minimal version for binary serialization. --- .../QuikGraph.Serialization.csproj | 10 +++++++--- src/QuikGraph.Serialization/SerializationExtensions.cs | 10 ++++++++++ .../BinarySerializationTests.cs | 2 ++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj index 663bd2f8d..d4b0812f7 100644 --- a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj +++ b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj @@ -1,7 +1,7 @@ - net35;net40;netstandard1.3;netstandard2.0;netstandard2.1 + net35;net40;net461;netstandard1.3;netstandard2.0;netstandard2.1 $(Generate_QuikGraph_Serialization) @@ -42,12 +42,16 @@ Updates: QuikGraph.Serialization .NET 3.5 - $(DefineConstants);NET35;SUPPORTS_SERIALIZATION;SUPPORTS_GRAPHS_SERIALIZATION;$(AdditionalConstants) + $(DefineConstants);NET35;SUPPORTS_SERIALIZATION;SUPPORTS_GRAPHS_SERIALIZATION;DEPRECATE_BINARY_SERIALIZATION;$(AdditionalConstants) true QuikGraph.Serialization .NET 4.0 - $(DefineConstants);NET40;SUPPORTS_SERIALIZATION;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) + $(DefineConstants);NET40;SUPPORTS_SERIALIZATION;SUPPORTS_GRAPHS_SERIALIZATION;DEPRECATE_BINARY_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) + + + QuikGraph.Serialization .NET 4.6.1 + $(DefineConstants);NET461;SUPPORTS_SERIALIZATION;SUPPORTS_GRAPHS_SERIALIZATION;SUPPORTS_XML_DTD_PROCESSING;$(AdditionalConstants) QuikGraph.Serialization .NET Standard 1.3 diff --git a/src/QuikGraph.Serialization/SerializationExtensions.cs b/src/QuikGraph.Serialization/SerializationExtensions.cs index 71c1cf496..6f3dff698 100644 --- a/src/QuikGraph.Serialization/SerializationExtensions.cs +++ b/src/QuikGraph.Serialization/SerializationExtensions.cs @@ -26,6 +26,11 @@ public static class SerializationExtensions /// is . /// is . /// is not writable. +#if DEPRECATE_BINARY_SERIALIZATION + [Obsolete( + "Binary serialization on old .NET targets is deprecated.\n" + + "Consider using another kind of serialization or updating to at least .NET Framework 4.6.1+, .NET Standard 2.0+ or .NET 5.0+.")] +#endif public static void SerializeToBinary( [NotNull] this IGraph graph, [NotNull] Stream stream) @@ -61,6 +66,11 @@ public static void SerializeToBinary( /// is . /// is not readable. [Pure] +#if DEPRECATE_BINARY_SERIALIZATION + [Obsolete( + "Binary deserialization on old .NET targets is deprecated.\n" + + "Consider using another kind of serialization or updating to at least .NET Framework 4.6.1+, .NET Standard 2.0+ or .NET 5.0+.")] +#endif public static TGraph DeserializeFromBinary( [NotNull] this Stream stream, [CanBeNull] SerializationBinder binder = null) diff --git a/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs index e7c49a3ad..d659145e5 100644 --- a/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs +++ b/tests/QuikGraph.Serialization.Tests/BinarySerializationTests.cs @@ -4,6 +4,8 @@ using NUnit.Framework; using static QuikGraph.Serialization.Tests.SerializationTestCaseSources; +#pragma warning disable 618 // Obsolete API usage + namespace QuikGraph.Serialization.Tests { /// From 352b29367f8f3440b1514b664abb8bf6327b91cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Rab=C3=A9rin?= Date: Mon, 4 Jul 2022 00:10:50 +0200 Subject: [PATCH 39/39] Write release notes for QuikGraph modules. --- RELEASE_NOTES.md | 124 ++++++++++++++++++ src/QuikGraph.Data/QuikGraph.Data.csproj | 7 +- .../QuikGraph.Graphviz.csproj | 12 +- src/QuikGraph.MSAGL/QuikGraph.MSAGL.csproj | 10 +- src/QuikGraph.Petri/QuikGraph.Petri.csproj | 7 +- .../QuikGraph.Serialization.csproj | 17 ++- src/QuikGraph/QuikGraph.csproj | 18 +-- 7 files changed, 165 insertions(+), 30 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 66f1f0e39..a5269f5a6 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,127 @@ # Release notes +## What's new in 2.5.0 July 4 2022 + +### QuikGraph + +#### Updates: +* Input type for transitive closure/reduction algorithms is more open (IEdgeListGraph rather than BidirectionalGraph). +* CryptoRandom no more use deprecate random number generator. +* Extends algorithms using CrytoRandom by default (CyclePoppingRandomTreeAlgorithm, MarkovEdgeChainBase, MinimumVertexCoverApproximationAlgorithm). + +#### New: +* Add cycle checking for edge set and undirected graphs (DAG - Directed Acyclic Graph check). + +#### Misc: +* Assembly is CLS compliant (Common Language Specification). + +### QuikGraph.Serialization + +#### Fixes: +* Fix fields being written several times during GraphML serialization for types with multiple inheritance layers. +* Fix user data that may be skipped during GraphML deserialization. +* Better handle null strings being serialized through GraphML serialization. + +#### Updates: +* Deprecate binary serialization for targets lower than .NET Framework 4.6.1. +* Update package dependencies. + +#### Optims: +* Optimize generated method calls for GraphML serialization. + +#### Misc: +* Add target .NET Framework 4.6.1. +* Assembly is CLS compliant (Common Language Specification). + +### QuikGraph.Graphviz + +#### Updates: +* Deprecate ToSvg API (underlying web service is down). +* Update package dependencies. + +#### Misc: +* Assembly is CLS compliant (Common Language Specification). + +### QuikGraph.Data + +#### Updates: +* Update package dependencies. + +#### Misc: +* Assembly is CLS compliant (Common Language Specification). + +### QuikGraph.MSAGL + +#### Updates: +* Update package dependencies. + +#### Misc: +* Assembly is CLS compliant (Common Language Specification). + +### QuikGraph.Petri + +#### Updates: +* Update package dependencies. + +#### Misc: +* Assembly is CLS compliant (Common Language Specification). + +--- + +## What's new in 2.4.0 July 3 2022 + +### QuikGraph + +#### Updates: +* Vertices and edges removal notifications from AdjacencyGraph, EdgeListGraph, BidirectionalGraph and UndirectedGraph are more consistent. + +#### Optims: +* Optimize vertices and/or edges removal operations on AdjacencyGraph, BidirectionalGraph, BidirectionalMatrixGraph, ClusteredAdjacencyGraph and UndirectedGraph. + +#### New: +* Expose a Prim relaxer. + +#### Misc: +* Improve library documentation related to raisable exceptions. +* Remove the dependency to System.Reflection.TypeExtensions for .NET Standard 1.3 target. + +### QuikGraph.Serialization + +#### Updates: +* GraphML deserialization extensions now work on IMutableVertexAndEdgeSet rather than IMutableVertexAndEdgeListGraph (allow deserialization on undirected graph). +* Update package dependencies. + +#### Misc: +* Add target to reduce dependencies in some cases. + +### QuikGraph.Graphviz + +#### Fixes: +* Fix the conversion to Graphviz from delegate graph implementations. + +#### Optims: +* Slight optimizations. + +#### Updates: +* Update package dependencies. + +### QuikGraph.Data + +#### Updates: +* Update package dependencies. + +### QuikGraph.MSAGL + +#### Updates: +* Update package dependencies. + +### QuikGraph.Petri + +#### Updates: +* Update package dependencies. + +--- + ## What's new in 2.3.1 August 30 2021 ### QuikGraph.Graphviz @@ -13,6 +135,8 @@ #### New: * Add support of HTML labels. +--- + ## What's new in 2.3.0 February 4 2021 ### QuikGraph diff --git a/src/QuikGraph.Data/QuikGraph.Data.csproj b/src/QuikGraph.Data/QuikGraph.Data.csproj index a358f4d50..8fe765507 100644 --- a/src/QuikGraph.Data/QuikGraph.Data.csproj +++ b/src/QuikGraph.Data/QuikGraph.Data.csproj @@ -28,9 +28,12 @@ Supports Source Link true QuikGraph.Data - ➟ Release 2.3.0 + ➟ Release 2.5.0 Updates: -- Update package dependencies. +- Update package dependencies. + +Misc: +- Assembly is CLS compliant (Common Language Specification). QuickGraph QuikGraph Graph Structure Algorithm C# .NET Serialization Data diff --git a/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj b/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj index 9376eeb63..1fc988bd1 100644 --- a/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj +++ b/src/QuikGraph.Graphviz/QuikGraph.Graphviz.csproj @@ -28,15 +28,13 @@ Supports Source Link true QuikGraph.Graphviz - ➟ Release 2.3.1 -Fixes: -- Properly treat common vertex format when converting a graph to Graphviz. - + ➟ Release 2.5.0 Updates: -- Label has priority if set over Record on GraphvizVertex. +- Deprecate ToSvg API (underlying web service is down). +- Update package dependencies. -New: -- Add support of HTML labels. +Misc: +- Assembly is CLS compliant (Common Language Specification). QuickGraph QuikGraph Graph Structure Algorithm C# .NET Serialization Graphviz diff --git a/src/QuikGraph.MSAGL/QuikGraph.MSAGL.csproj b/src/QuikGraph.MSAGL/QuikGraph.MSAGL.csproj index 116f1e420..85da331d6 100644 --- a/src/QuikGraph.MSAGL/QuikGraph.MSAGL.csproj +++ b/src/QuikGraph.MSAGL/QuikGraph.MSAGL.csproj @@ -28,12 +28,12 @@ Supports Source Link true QuikGraph.MSAGL - ➟ Release 2.3.0 -Fixes: -- Update reference to AutomaticGraphLayout packages in order to fix assembly strong naming issues. - + ➟ Release 2.5.0 Updates: -- Update package dependencies. +- Update package dependencies. + +Misc: +- Assembly is CLS compliant (Common Language Specification). QuickGraph QuikGraph Graph Structure Algorithm C# .NET MSAGL diff --git a/src/QuikGraph.Petri/QuikGraph.Petri.csproj b/src/QuikGraph.Petri/QuikGraph.Petri.csproj index b8426e8bd..44185bb93 100644 --- a/src/QuikGraph.Petri/QuikGraph.Petri.csproj +++ b/src/QuikGraph.Petri/QuikGraph.Petri.csproj @@ -28,9 +28,12 @@ Supports Source Link true QuikGraph.Petri - ➟ Release 2.3.0 + ➟ Release 2.5.0 Updates: -- Update package dependencies. +- Update package dependencies. + +Misc: +- Assembly is CLS compliant (Common Language Specification). QuickGraph QuikGraph Graph Structure Algorithm C# .NET Petri diff --git a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj index d4b0812f7..fd7aa7d1f 100644 --- a/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj +++ b/src/QuikGraph.Serialization/QuikGraph.Serialization.csproj @@ -28,9 +28,22 @@ Supports Source Link true QuikGraph.Serialization - ➟ Release 2.3.0 + ➟ Release 2.5.0 +Fixes: +- Fix fields being written several times during GraphML serialization for types with multiple inheritance layers. +- Fix user data that may be skipped during GraphML deserialization. +- Better handle null strings being serialized through GraphML serialization. + Updates: -- Update package dependencies. +- Deprecate binary serialization for targets lower than .NET Framework 4.6.1. +- Update package dependencies. + +Optims: +- Optimize generated method calls for GraphML serialization. + +Misc: +- Add target .NET Framework 4.6.1. +- Assembly is CLS compliant (Common Language Specification). QuickGraph QuikGraph Graph Structure Algorithm C# .NET Serialization diff --git a/src/QuikGraph/QuikGraph.csproj b/src/QuikGraph/QuikGraph.csproj index ba0952f08..f72df7124 100644 --- a/src/QuikGraph/QuikGraph.csproj +++ b/src/QuikGraph/QuikGraph.csproj @@ -34,23 +34,17 @@ Supports Source Link true QuikGraph - ➟ Release 2.3.0 -Fixes: -- Fix the serialization implementation of UndirectedGraph, ArrayUndirectedGraph and UndirectedBidirectionalGraph. -- Fix A* implementation to also compute cost on tree edge. - + ➟ Release 2.5.0 Updates: -- Remove some serializable attributes from algorithms and predicates classes (homognization). -- Remove serializable attributes from delegate graphs implementations. -- All QuikGraph exceptions can be constructed with a custom message and an eventual inner exception. -- CompressedSparseRowGraph also implements IEdgeListGraph interface. -- EquateGraphs.Equate helpers now supports a wider range of graph comparisons. +- Input type for transitive closure/reduction algorithms is more open (IEdgeListGraph rather than BidirectionalGraph). +- CryptoRandom no more use deprecate random number generator. +- Extends algorithms using CrytoRandom by default (CyclePoppingRandomTreeAlgorithm, MarkovEdgeChainBase, MinimumVertexCoverApproximationAlgorithm). New: -- Add the IDistancesCollection to interface the distance information retrieval from shortest path algorithms. Legacy accesses to distances are marked as obsolete. +- Add cycle checking for edge set and undirected graphs (DAG - Directed Acyclic Graph check). Misc: -- Remove the dependency to System.Collections.NonGeneric for .NET Standard 1.3 target. +- Assembly is CLS compliant (Common Language Specification). QuickGraph QuikGraph Graph Structure Algorithm C# .NET