/// <summary> /// Декодировать пути между элементами секций хромосомы. /// </summary> /// <param name="chromosome">Декодируемая хромосома.</param> protected void DecodePathes(TopologyChromosome chromosome) { try { // Группируем секции по частям с УСПД и перебираем группы foreach (var dadGroup in Sections.GroupBy(q => q.DADPart, new DataAcquisitionSectionPartComparer())) { var pathes = new List <TopologyPath>(); foreach (var channelGroup in dadGroup.GroupBy(w => w.Channel)) // Группы секций группируем по каналам передачи данных, которые связывают КУ и УСПД { // Находим путь между УСПД и всеми КУ по каждому каналу передачи в группе секций var path = TopologyPathfinder.GetShortestPath(chromosome.CurrentProject.Graph, dadGroup.Key.Vertex, channelGroup.Select(q => q.MCDPart.Vertex), channelGroup.Key); if (path != null) { pathes.AddRange(path); } } Pathes.Add(dadGroup.Key, pathes); } } catch (Exception ex) { Console.WriteLine("DecodePathes failed! {0}", ex.Message); } }
/// <summary> /// Проверить, что КУ и УСПД могут связываться по данному КПД, найти путь от КПД до всех КУ и рассчитать его стоимость. /// </summary> /// <param name="project">Свойства текущего проекта.</param> /// <param name="dadPart">Часть секции с УСПД.</param> /// <param name="dataChannel">Канал, соединяющий УСПД и КУ.</param> /// <param name="connectedMCDs">Соединяемые с УСПД КУ по КПД.</param> /// <returns>Стоимость путей от УСПД до КУ по КПД.</returns> protected double GetConnectionCost(Project project, DataAcquisitionSectionPart dadPart, MeasurementAndControlSectionPart[] connectedMCDs, DataChannel dataChannel) { try { if (connectedMCDs.Any(q => !q.MCD.SendingCommunications.Contains(dataChannel.Communication))) // Если есть хоть одно КУ, которое не поддерживает канал, то дальше можно не смотреть { return(3 * UNACCEPTABLE); } if (!dadPart.DAD.ReceivingCommunications.Keys.Contains(dataChannel.Communication)) // Если УСПД не поддерживает данный канал, дальше можно не смотреть { return(2 * UNACCEPTABLE); } var dadUsedCommunication = dadPart.DAD.ReceivingCommunications.Single(q => q.Key == dataChannel.Communication); // Проверить, что УСПД поддерживает количество подключенных устройств по КПД if (connectedMCDs.Length > dadUsedCommunication.Value) { return(VERY_BAD * (connectedMCDs.Length - dadUsedCommunication.Value)); } // Найти все пути, соединяющие УСПД и все КУ, присоединённые по данному КПД var pathes = TopologyPathfinder.GetShortestPath(project.Graph, dadPart.Vertex, connectedMCDs.Select(q => q.Vertex), dataChannel); // Проверить длину пути и проходимость сквозь участки беспроводной связи var distance = GetMinDistance(pathes, dataChannel); if (distance > dataChannel.MaxRange) { return(distance * BAD); // Чем дальше, тем хуже значение фитнес-функции } return(pathes?.Sum(q => q.GetCost(project)) ?? UNACCEPTABLE); // Вернуть сумму стоимостей всех составных частей пути, если путь не найден, то плохо - высокая стоимость } catch (Exception ex) { Console.WriteLine("GetConnectionCost failed! {0}", ex.Message); return(10 * UNACCEPTABLE); } }
/// <summary> /// Сгруппировать УСПД одной модели, расположенные на одном участке. /// </summary> /// <param name="chromosome">Декодириуемая хромосома.</param> protected void GroupDADs(TopologyChromosome chromosome) { try { var dadSectionPartGroups = Sections .Select((section, Index) => new { Part = section.DADPart, Index }) // Запоминаем и индекс секции .GroupBy(q => q.Part.DAD) // Группируем секции с одинаковым УСПД .Where(q => q.Count() > 1); // Берём те группы, если хоть какие-то УСПД сгруппировали foreach (var dadSectionPartGroup in dadSectionPartGroups) { // Далее группируем по участкам и берём те группы, где их больше 1 и где они ещё не на одной вершине var regionSectionPartGroups = dadSectionPartGroup .GroupBy(q => q.Part.Vertex.Region) .Where(q => q.Count() > 1); foreach (var regionSectionPartGroup in regionSectionPartGroups) { // Если все устройства и так уже в одной вершине, пропускаем эту группу var firstVertex = dadSectionPartGroup.FirstOrDefault()?.Part.Vertex; if (firstVertex == null || regionSectionPartGroup.All(q => q.Part.Vertex == firstVertex)) { continue; } var dadsBus = TopologyPathfinder.GetShortestPath( // Находим кратчайший путь chromosome.CurrentProject.Graph, firstVertex, // Из первой вершины в группе regionSectionPartGroup .Select(q => q.Part.Vertex) // До остальных вершин в группе .Distinct() // Без повторяющихся вершин и без исходной вершины .Where(q => q != firstVertex), // По топологии шина и учитывая только расстояние new DataChannel { ConnectionType = ConnectionType.None, Topology = DataChannelTopology.Bus }); // Берём все грани пути и выбираем из них целевые вершины var pathVertices = dadsBus.Where(q => q.Path != null).SelectMany(q => q.Path).Select(q => q.Target).ToList(); pathVertices.Add(firstVertex); // И добавляем исходную вершину var minVertexWeight = pathVertices.Min(q => q.LaboriousnessWeight); // Определяем самый малый вес у вершин пути // Находим все вершины с наименьшим весом var minWeightVertices = pathVertices.Where(q => q.LaboriousnessWeight == minVertexWeight); // Выбираем случайно одну вершину из тех, что с наименьшим весом var randomOptimalVertex = minWeightVertices.ElementAt(RandomizationProvider.Current.GetInt(0, minWeightVertices.Count())); // Перемещаем все УСПД, которые ещё не в оптимальной вершине, в эту вершину, чтобы они стали одним УСПД foreach (var sectionPart in regionSectionPartGroup.Where(q => q.Part.Vertex != randomOptimalVertex)) { sectionPart.Part.Move(randomOptimalVertex); // Определяем индекс вершины в упорядоченном массиве вершин var index = Array.IndexOf(chromosome.CurrentProject.Graph.VerticesArray, randomOptimalVertex); // Модифицируем хромосому тоже, находим ген позиции УСПД и обновляем индекс новой вершины chromosome.ReplaceGene(sectionPart.Index * TopologyChromosome.GENES_IN_SECTION + 3, new GeneticSharp.Domain.Chromosomes.Gene(index)); } } } } catch (Exception ex) { Console.WriteLine("GroupDADs failed! {0}", ex.Message); } }