/// <summary> /// Создать и проинициализировать элемент кэша путей в графе. /// </summary> /// <param name="source">Вершина графа - источник пути.</param> /// <param name="target">Вершина пути - цель пути.</param> /// <param name="connectionType">Тип связи в данном пути.</param> /// <param name="path">Перечисление граней графа, составляющих путь.</param> public TopologyPathesCacheItem(TopologyVertex source, TopologyVertex target, ConnectionType connectionType, IEnumerable <TopologyEdge> path) { Source = source; Target = target; ConnectionType = connectionType; Path = path; }
/// <summary> /// Найти кратчайший путь по смешанной топологии. /// </summary> /// <param name="graph">Граф, в котором ищем путь.</param> /// <param name="source">Вершина графа с УСПД.</param> /// <param name="targets">Вершины КУ, которые нужно соединить кратчайшим путём.</param> /// <param name="dataChannel">Канал передачи данных, по которому соеденяются КУ и УСПД.</param> /// <returns>Перечисление путей в графе.</returns> private static IEnumerable <TopologyPath> MeshShortestPath(TopologyGraph graph, TopologyVertex source, IEnumerable <TopologyVertex> targets, DataChannel dataChannel) { try { // Кандидаты составных частей сети, где ключ - пара источника и целевой вершины, а значение - путь между ними var meshPartCandidates = new Dictionary <KeyValuePair <TopologyVertex, TopologyVertex>, IEnumerable <TopologyEdge> >(); var mesh = new List <TopologyPath>(); // Итоговая сеть смешанной топологии var meshPartSources = new List <TopologyVertex> { source }; // Все возможные источники сети var remainedTargets = new List <TopologyVertex>(targets); // Оставшиеся целевые вершины for (var i = 0; i < targets.Count(); i++) // Пока не переберём все целевые вершины { foreach (var partSource in meshPartSources) // Перебираем все имеющиеся источники сети { foreach (var target in remainedTargets) // Перебираем все оставшиеся целевые вершины { var path = GetShortestPath(graph, partSource, target, dataChannel.ConnectionType); // Ищем кратчайший путь из источника в цель и сохраняем его как кандидат на кратчайший meshPartCandidates.Add(new KeyValuePair <TopologyVertex, TopologyVertex>(partSource, target), path); } } // Находим минимальный вес среди кандидатов, причём, если источник и цель в одной вершине - вес нулевой var minWeight = meshPartCandidates.Min(candidate => candidate.Value?.Sum(edge => edge.Weights[dataChannel.ConnectionType]) ?? 0); // Определяем путь с минимальным весом и добавляем в шину var shortestPath = meshPartCandidates.FirstOrDefault(candidate => (candidate.Value?.Sum(edge => edge.Weights[dataChannel.ConnectionType]) ?? 0) == minWeight); var shortestPathSource = shortestPath.Key.Key; // Источник находится в ключе пары найденного пути, где сам является ключем var shortestPathTarget = shortestPath.Key.Value; // Целевая вершина находится в ключе пары найденного пути, где является значением mesh.Add(new TopologyPath { DataChannel = dataChannel, Path = shortestPath.Value, Source = shortestPathSource, Target = shortestPathTarget }); // Вершина-источник найденной части сети тоже теперь может являться источником, если ещё не является if (!meshPartSources.Contains(shortestPathTarget)) { meshPartSources.Add(shortestPathTarget); } remainedTargets.Remove(shortestPathTarget); // Больше не рассматриваем целевую вершину из найденной части сети meshPartCandidates.Clear(); // Ищем кандидатов заново } return(mesh); } catch (Exception ex) { Console.WriteLine("MeshShortestPath failed! {0}", ex.Message); return(null); } }
/// <summary> /// Найти кратчайший путь в секции от вершины источника - УСПД, через все целевые вершины КУ. /// </summary> /// <param name="graph">Граф, в котором ищем путь.</param> /// <param name="source">Вершина графа с УСПД.</param> /// <param name="targets">Вершины КУ, которые нужно соединить кратчайшим путём.</param> /// <param name="dataChannel">Канал передачи данных, по которому соеденяются КУ и УСПД.</param> /// <returns>Перечисление путей в графе.</returns> public static IEnumerable <TopologyPath> GetShortestPath(TopologyGraph graph, TopologyVertex source, IEnumerable <TopologyVertex> targets, DataChannel dataChannel) { try { switch (dataChannel.Topology) { case DataChannelTopology.Mesh: return(MeshShortestPath(graph, source, targets, dataChannel)); case DataChannelTopology.Star: return(StarShortestPath(graph, source, targets, dataChannel)); case DataChannelTopology.Bus: return(BusShortestPath(graph, source, targets, dataChannel)); default: return(null); } } catch (Exception ex) { Console.WriteLine("SectionShortestPath failed! {0}", ex.Message); return(null); } }
/// <summary> /// Найти кратчайший путь из источника в цель в кеше или на графе. /// </summary> /// <param name="source">Вершина графа - источник пути.</param> /// <param name="target">Вершина пути - цель пути.</param> /// <param name="connectionType">Тип связи.</param> /// <returns>Найденный заново или взятый из кэша путь.</returns> public static IEnumerable <TopologyEdge> GetShortestPath(TopologyGraph graph, TopologyVertex source, TopologyVertex target, ConnectionType connectionType) { try { var cachedPath = PathesCache.SingleOrDefault(q => // Пытаемся найти такой прямой или обратный путь в кэше q.ConnectionType == connectionType && ((q.Source == source && q.Target == target) || (q.Target == source && q.Source == target))); if (cachedPath != null) { return(cachedPath.Path); } // Если не нашли, ищем путь в графе var tryGetPath = graph.ShortestPathsDijkstra((edge) => { return(edge.Weights[connectionType]); }, source); tryGetPath(target, out var path); // Сохраняем найденный путь в кэше и возвращаем PathesCache.Add(new TopologyPathesCacheItem(source, target, connectionType, path)); return(path); } catch (Exception ex) { Console.WriteLine("GetPath failed! {0}", ex.Message); return(null); } }
/// <summary> /// Найти кратчайший путь по топологии "Шина". /// </summary> /// <param name="graph">Граф, в котором ищем путь.</param> /// <param name="source">Вершина графа с УСПД.</param> /// <param name="targets">Вершины КУ, которые нужно соединить кратчайшим путём.</param> /// <param name="dataChannel">Канал передачи данных, по которому соеденяются КУ и УСПД.</param> /// <returns>Перечисление путей в графе.</returns> private static IEnumerable <TopologyPath> BusShortestPath(TopologyGraph graph, TopologyVertex source, IEnumerable <TopologyVertex> targets, DataChannel dataChannel) { try { var bus = new List <TopologyPath>(); // Итоговая шина, состоящая из составных частей - путей между вершинами шины var busPartCandidates = new Dictionary <TopologyVertex, IEnumerable <TopologyEdge> >(); // Кандидаты на составные части шины, где ключ - целевая вершина, значение - путь до неё var busPartSource = source; // Текущая вершина-источник части шины var remainedTargets = new List <TopologyVertex>(targets); // Оставшиеся целевые вершины for (var i = 0; i < targets.Count(); i++) // Пока не переберём все целевые вершины { foreach (var target in remainedTargets) // Перебираем все оставшиеся целевые вершины { var path = GetShortestPath(graph, busPartSource, target, dataChannel.ConnectionType); // Ищем кратчайший путь из источника в цель и сохраняем его как кандидат на кратчайший busPartCandidates.Add(target, path); } // Находим минимальный вес среди кандидатов, причём, если источник и цель в одной вершине - вес нулевой var minWeight = busPartCandidates.Min(candidate => candidate.Value?.Sum(edge => edge.Weights[dataChannel.ConnectionType]) ?? 0); // Определяем путь с минимальным весом и добавляем в шину var shortestPath = busPartCandidates.FirstOrDefault(candidate => (candidate.Value?.Sum(edge => edge.Weights[dataChannel.ConnectionType]) ?? 0) == minWeight); var shortestPathTarget = shortestPath.Key; // Целевая вершина находится в ключе найденной пары пути bus.Add(new TopologyPath { DataChannel = dataChannel, Path = shortestPath.Value, Source = busPartSource, Target = shortestPathTarget }); busPartSource = shortestPathTarget; // Целевая вершина найденного пути теперь источник remainedTargets.Remove(shortestPathTarget); // Убираем эту вершину из оставшихся целевых вершин busPartCandidates.Clear(); // Ищем кандидатов заново } return(bus); } catch (Exception ex) { Console.WriteLine("BusShortestPath failed! {0}", ex.Message); return(null); } }
/// <summary> /// Найти кратчайший путь по топологии "Звезда". /// </summary> /// <param name="graph">Граф, в котором ищем путь.</param> /// <param name="source">Вершина графа с УСПД.</param> /// <param name="targets">Вершины КУ, которые нужно соединить кратчайшим путём.</param> /// <param name="dataChannel">Канал передачи данных, по которому соеденяются КУ и УСПД.</param> /// <returns>Перечисление путей в графе.</returns> private static IEnumerable <TopologyPath> StarShortestPath(TopologyGraph graph, TopologyVertex source, IEnumerable <TopologyVertex> targets, DataChannel dataChannel) { try { // Задаём результирующий контейнер путей, источник и алгоритм расчёта весов var resultPath = new List <TopologyPath>(); foreach (var target in targets) // Для звезды находим пути из источника ко всем целям { var path = GetShortestPath(graph, source, target, dataChannel.ConnectionType); resultPath.Add(new TopologyPath { DataChannel = dataChannel, Path = path, Source = source, Target = target }); } return(resultPath); } catch (Exception ex) { Console.WriteLine("StarShortestPath failed! {0}", ex.Message); return(null); } }