<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YAGLi.EdgeComparers;
using YAGLi.Extensions;
using YAGLi.Interfaces;

namespace YAGLi
{
    /// <summary>
    /// The class <see cref="UndirectedGraph{TVertex}"/> models graph in which edges have no direction.
    /// The edge (x -- y) is equal to the edge (y -- x).
    /// </summary>
    /// <typeparam name="TVertex">The type of the vertex that the graph store.</typeparam>
    public class UndirectedGraph<TVertex, TEdge> : IModelAUndirectedGraph<TVertex, TEdge> where TEdge : IModelAnEdge<TVertex>
    {
        #region Constants
        private const int UNDIRECTED_GRAPHS_HASH_BASE = 101;
        private const int UNDIRECTED_GRAPHS_HASH_FACTOR = 107;
        #endregion

        #region Instance fields
        /// <summary>
        /// Readonly field who store the incident edges of each vertex contained in this instance.
        /// </summary>
        private readonly IReadOnlyDictionary<TVertex, IEnumerable<TEdge>> _incidentEdges;

        /// <summary>
        /// Readonly field who hold the edge comparison logic specific of this instance.
        /// </summary>
        private readonly IEqualityComparer<TEdge> _edgesComparer;

        /// <summary>
        /// Readonly field who store the object who hold the comparison logic for the vertices.
        /// </summary>
        private readonly IEqualityComparer<TVertex> _verticesComparer;
        #endregion

        #region Constructors
        public UndirectedGraph(bool allowLoops, bool allowParallelEdges) : this(allowLoops, allowParallelEdges, EqualityComparer<TVertex>.Default) { }

        public UndirectedGraph(bool allowLoops, bool allowParallelEdges, IEqualityComparer<TVertex> verticesComparer) : this(allowLoops, allowParallelEdges, Enumerable.Empty<TEdge>(), Enumerable.Empty<TVertex>(), verticesComparer) { }

        public UndirectedGraph(bool allowLoops, bool allowParallelEdges, IEnumerable<TEdge> edges, IEnumerable<TVertex> vertices) : this(allowLoops, allowParallelEdges, edges, vertices, EqualityComparer<TVertex>.Default) { }

        public UndirectedGraph(bool allowLoops, bool allowParallelEdges, IEnumerable<TEdge> edges, IEnumerable<TVertex> vertices, IEqualityComparer<TVertex> verticesComparer)
        {
            AllowLoops = allowLoops;
            AllowParallelEdges = allowParallelEdges;

            verticesComparer = verticesComparer ?? EqualityComparer<TVertex>.Default;
            edges = edges.ReplaceByEmptyIfNull();
            vertices = vertices.ReplaceByEmptyIfNull();

            _edgesComparer = AllowParallelEdges ? new IgnoreDirectionAndAllowParallelEdges<TVertex, TEdge>(verticesComparer) as IEqualityComparer<TEdge> : new IgnoreDirectionAndDisallowParallelEdges<TVertex, TEdge>(verticesComparer);
            _verticesComparer = verticesComparer;

            edges = edges.FilterNulls();
            vertices = vertices.FilterNulls();

            var incidentEdges = new Dictionary<TVertex, IList<TEdge>>(_verticesComparer);
            var distinctEdges = AllowParallelEdges ? edges : edges.Distinct(_edgesComparer);

            foreach (var edge in (!AllowLoops ? distinctEdges.Where(edge => !_verticesComparer.Equals(edge.End1, edge.End2)) : distinctEdges))
            {
                var distinctEnds = _verticesComparer.Equals(edge.End1, edge.End2) ? edge.End1.Yield() : new TVertex[] { edge.End1, edge.End2 };

                foreach (var end in distinctEnds)
                {
                    if (!incidentEdges.ContainsKey(end))
                    {
                        incidentEdges[end] = new List<TEdge>();
                    }

                    incidentEdges[end].Add(edge);
                }
            }

            foreach (var vertex in vertices.Where(vertex => !incidentEdges.ContainsKey(vertex)))
            {
                incidentEdges.Add(vertex, new List<TEdge>(0));
            }

            _incidentEdges = incidentEdges.ToDictionary(x => x.Key, x => x.Value.AsEnumerable(), _verticesComparer);
        }
        #endregion

        #region Properties
        public bool AllowLoops { get; }

        public bool AllowParallelEdges { get; }

        public IEnumerable<TEdge> Edges
        {
            get
            {
                return _incidentEdges
                    .Values
                    .SelectMany(x => x)
                    .Distinct(_edgesComparer);
            }
        }

        public IEnumerable<TVertex> Vertices
        {
            get
            {
                return _incidentEdges.Keys;
            }
        }
        #endregion

        #region Methods
        public IEnumerable<TEdge> AdjacentEdgesOf(TEdge edge)
        {
            if (!ContainsEdge(edge))
            {
                return Enumerable.Empty<TEdge>();
            }

            return Edges
                .Except(edge.Yield(), _edgesComparer)
                .Where(x => areEdgesAdjacent(x, edge));
        }

        public IEnumerable<TVertex> AdjacentVerticesOf(TVertex vertex)
        {
            if (!ContainsVertex(vertex))
            {
                return Enumerable.Empty<TVertex>();
            }

            return _incidentEdges[vertex]
                .SelectMany(edge => new TVertex[] { edge.End1, edge.End2 })
                .Where(v => !_verticesComparer.Equals(v, vertex));
        }

        public UndirectedGraph<TVertex, TEdge> AddEdge(TEdge edge)
        {
            return AddEdges(edge.Yield());
        }

        public UndirectedGraph<TVertex, TEdge> AddEdgeAndVertices(TEdge edge)
        {
            return AddEdgesAndVertices(edge.Yield());
        }

        private UndirectedGraph<TVertex, TEdge> addEdges(IEnumerable<TEdge> edges)<commit_msg>Used a more appropriate Linq fucntion<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YAGLi.EdgeComparers;
using YAGLi.Extensions;
using YAGLi.Interfaces;

namespace YAGLi
{
    /// <summary>
    /// The class <see cref="UndirectedGraph{TVertex}"/> models graph in which edges have no direction.
    /// The edge (x -- y) is equal to the edge (y -- x).
    /// </summary>
    /// <typeparam name="TVertex">The type of the vertex that the graph store.</typeparam>
    public class UndirectedGraph<TVertex, TEdge> : IModelAUndirectedGraph<TVertex, TEdge> where TEdge : IModelAnEdge<TVertex>
    {
        #region Constants
        private const int UNDIRECTED_GRAPHS_HASH_BASE = 101;
        private const int UNDIRECTED_GRAPHS_HASH_FACTOR = 107;
        #endregion

        #region Instance fields
        /// <summary>
        /// Readonly field who store the incident edges of each vertex contained in this instance.
        /// </summary>
        private readonly IReadOnlyDictionary<TVertex, IEnumerable<TEdge>> _incidentEdges;

        /// <summary>
        /// Readonly field who hold the edge comparison logic specific of this instance.
        /// </summary>
        private readonly IEqualityComparer<TEdge> _edgesComparer;

        /// <summary>
        /// Readonly field who store the object who hold the comparison logic for the vertices.
        /// </summary>
        private readonly IEqualityComparer<TVertex> _verticesComparer;
        #endregion

        #region Constructors
        public UndirectedGraph(bool allowLoops, bool allowParallelEdges) : this(allowLoops, allowParallelEdges, EqualityComparer<TVertex>.Default) { }

        public UndirectedGraph(bool allowLoops, bool allowParallelEdges, IEqualityComparer<TVertex> verticesComparer) : this(allowLoops, allowParallelEdges, Enumerable.Empty<TEdge>(), Enumerable.Empty<TVertex>(), verticesComparer) { }

        public UndirectedGraph(bool allowLoops, bool allowParallelEdges, IEnumerable<TEdge> edges, IEnumerable<TVertex> vertices) : this(allowLoops, allowParallelEdges, edges, vertices, EqualityComparer<TVertex>.Default) { }

        public UndirectedGraph(bool allowLoops, bool allowParallelEdges, IEnumerable<TEdge> edges, IEnumerable<TVertex> vertices, IEqualityComparer<TVertex> verticesComparer)
        {
            AllowLoops = allowLoops;
            AllowParallelEdges = allowParallelEdges;

            verticesComparer = verticesComparer ?? EqualityComparer<TVertex>.Default;
            edges = edges.ReplaceByEmptyIfNull();
            vertices = vertices.ReplaceByEmptyIfNull();

            _edgesComparer = AllowParallelEdges ? new IgnoreDirectionAndAllowParallelEdges<TVertex, TEdge>(verticesComparer) as IEqualityComparer<TEdge> : new IgnoreDirectionAndDisallowParallelEdges<TVertex, TEdge>(verticesComparer);
            _verticesComparer = verticesComparer;

            edges = edges.FilterNulls();
            vertices = vertices.FilterNulls();

            var incidentEdges = new Dictionary<TVertex, IList<TEdge>>(_verticesComparer);
            var distinctEdges = AllowParallelEdges ? edges : edges.Distinct(_edgesComparer);

            foreach (var edge in (!AllowLoops ? distinctEdges.Where(edge => !_verticesComparer.Equals(edge.End1, edge.End2)) : distinctEdges))
            {
                var distinctEnds = _verticesComparer.Equals(edge.End1, edge.End2) ? edge.End1.Yield() : new TVertex[] { edge.End1, edge.End2 };

                foreach (var end in distinctEnds)
                {
                    if (!incidentEdges.ContainsKey(end))
                    {
                        incidentEdges[end] = new List<TEdge>();
                    }

                    incidentEdges[end].Add(edge);
                }
            }

            foreach (var vertex in vertices.Where(vertex => !incidentEdges.ContainsKey(vertex)))
            {
                incidentEdges.Add(vertex, new List<TEdge>(0));
            }

            _incidentEdges = incidentEdges.ToDictionary(x => x.Key, x => x.Value.AsEnumerable(), _verticesComparer);
        }
        #endregion

        #region Properties
        public bool AllowLoops { get; }

        public bool AllowParallelEdges { get; }

        public IEnumerable<TEdge> Edges
        {
            get
            {
                return _incidentEdges
                    .Values
                    .SelectMany(x => x)
                    .Distinct(_edgesComparer);
            }
        }

        public IEnumerable<TVertex> Vertices
        {
            get
            {
                return _incidentEdges.Keys;
            }
        }
        #endregion

        #region Methods
        public IEnumerable<TEdge> AdjacentEdgesOf(TEdge edge)
        {
            if (!ContainsEdge(edge))
            {
                return Enumerable.Empty<TEdge>();
            }

            return Edges
                .Except(edge.Yield(), _edgesComparer)
                .Where(x => areEdgesAdjacent(x, edge));
        }

        public IEnumerable<TVertex> AdjacentVerticesOf(TVertex vertex)
        {
            if (!ContainsVertex(vertex))
            {
                return Enumerable.Empty<TVertex>();
            }

            return _incidentEdges[vertex]
                .SelectMany(edge => new TVertex[] { edge.End1, edge.End2 })
                .Except(vertex.Yield(), _verticesComparer);
        }

        public UndirectedGraph<TVertex, TEdge> AddEdge(TEdge edge)
        {
            return AddEdges(edge.Yield());
        }

        public UndirectedGraph<TVertex, TEdge> AddEdgeAndVertices(TEdge edge)
        {
            return AddEdgesAndVertices(edge.Yield());
        }

        private UndirectedGraph<TVertex, TEdge> addEdges(IEnumerable<TEdge> edges)
{'fraction_non_alphanumeric': 0.09158266563280779, 'fraction_numerical': 0.0027569570087016457, 'mean_word_length': 2.2352285395763656, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 110, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2107349', 'n_tokens_mistral': 3251, 'n_tokens_neox': 3132, 'n_words': 695}