/// <summary> /// Декодировать текущую секцию из генотипа. /// </summary> /// <param name="chromosome">Декодируемая хромосома.</param> /// <param name="sectionIndex">Индекс секции в декодируемой хромосоме.</param> public void Decode(TopologyChromosome chromosome, int sectionIndex) { try { var sectionGenes = chromosome.GetGenes() // Получаем значения генов только данной секции .Select((gene, index) => new { Value = (int)gene.Value, Index = index }) .Where(q => GetSectionIndex(q.Index) == sectionIndex) .Select(q => q.Value) .ToArray(); if (sectionGenes.Length < GeneValueGenerationFuncs.Length) { throw new Exception("Incorrect section size!"); } // 0-й ген - тип КУ, 1-й ген - узел КУ, 2-й ген - тип УСПД, 3-й ген - узел УСПД, 4-й ген - КПД MCDPart.Decode(chromosome.CurrentProject, sectionGenes[0], sectionGenes[1]); DADPart.Decode(chromosome.CurrentProject, sectionGenes[2], sectionGenes[3]); Channel = chromosome.CurrentProject.Equipments.DCs[sectionGenes[4]]; } catch (Exception ex) { Console.WriteLine("TopologySection Decode failed! {0}", ex.Message); } }
/// <summary> /// Сгенерировать новый ген, представляющий случайную вершину графа, для расположения в ней УСПД. /// </summary> /// <param name="chromosome">Текущая хромосома.</param> /// <param name="sectionIndex">Индекс секции, для которой генерируется ген.</param> /// <returns>Целочисленное значение случайного гена, соответствующее индексу в массиве вершин графа.</returns> public static int GenerateVertexGene(TopologyChromosome chromosome, int sectionIndex) { try { // Выбираем случайный участок var randomRegionIndex = RandomizationProvider.Current.GetInt(0, chromosome.CurrentProject.Regions.Length); var randomRegion = chromosome.CurrentProject.Regions[randomRegionIndex]; // Берём все вершины участка var regionVertices = chromosome.CurrentProject.Graph.Vertices.Where(q => q.Region == randomRegion); var minVertexWeight = regionVertices.Min(q => q.LaboriousnessWeight); // Определяем самый малый вес у вершин участка // Находим все вершины с наименьшим весом var minWeightVertices = regionVertices.Where(q => q.LaboriousnessWeight == minVertexWeight); // Выбираем случайно одну вершину из тех, что с наименьшим весом return(RandomizationProvider.Current.GetInt(0, minWeightVertices.Count())); } catch (Exception ex) { Console.WriteLine("GenerateDAVertexGene failed! {0}", ex.Message); return(0); } }
/// <summary> /// Сгенерировать новый ген, представляющий случайный КПД для связьи устройства учёта и управления и УСПД, /// выбирается такой, чтобы подходил к устройству и к КПД. /// </summary> /// <param name="chromosome">Текущая хромосома.</param> /// <param name="sectionIndex">Индекс секции, для которой генерируется ген.</param> /// <returns>Целочисленное значение случайного гена, соответствующее индексу в массиве доступных каналов передачи данных.</returns> protected static int GenerateDataChannelGene(TopologyChromosome chromosome, int sectionIndex) { try { // Декодируем КУ из гена, которое выбрано в данной секции (оно идёт первым в хромосоме) var mcd = chromosome.CurrentProject.Equipments.MCDs[(int)chromosome.GetGene(sectionIndex * TopologyChromosome.GENES_IN_SECTION).Value]; // Декодируем УСПД из гена, которое выбрано в данной секции (оно идёт третьим в хромосоме) var dad = chromosome.CurrentProject.Equipments.DADs[(int)chromosome.GetGene(sectionIndex * TopologyChromosome.GENES_IN_SECTION + 2).Value]; // Выбираем те КПД, которые совместимы и с выбранным КУ, и с выбранным УСПД var suitableDataChannels = chromosome.CurrentProject.Equipments.DCs .Select((dataChannel, index) => new { DataChannel = dataChannel, Index = index }) .Where(indexedChannel => mcd.SendingCommunications.Contains(indexedChannel.DataChannel.Communication) && dad.ReceivingCommunications.Keys.Contains(indexedChannel.DataChannel.Communication)) .ToArray(); // Если не нашли подходящего УСПД, то выбираем случайный if (!suitableDataChannels.Any()) { return(RandomizationProvider.Current.GetInt(0, chromosome.CurrentProject.Equipments.DCs.Length)); } // Иначе берём случайный КПД из подходящих var randomIndex = RandomizationProvider.Current.GetInt(0, suitableDataChannels.Count()); return(suitableDataChannels[randomIndex].Index); } catch (Exception ex) { Console.WriteLine("GenerateDataChannelGene failed! {0}", ex.Message); return(0); } }
/// <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="chromosome">Текущая хромосома.</param> /// <param name="sectionIndex">Индекс секции, для которой генерируется ген.</param> /// <returns>Целочисленное значение случайного гена, соответствующее индексу в массиве УСПД.</returns> public static int GenerateDeviceGene(TopologyChromosome chromosome, int sectionIndex) { try { // Декодируем КУ из гена, которое выбрано в данной секции (оно идёт первым в хромосоме) var mcd = chromosome.CurrentProject.Equipments.MCDs[(int)chromosome.GetGene(sectionIndex * TopologyChromosome.GENES_IN_SECTION).Value]; // Выбираем только те УСПД, которые подходят для КУ var suitableDADs = chromosome.CurrentProject.Equipments.DADs .Select((dad, index) => new { DAD = dad, Index = index }) .Where(indexedDAD => indexedDAD.DAD.ReceivingCommunications.Keys.Any(communiction => mcd.SendingCommunications.Contains(communiction))) .ToArray(); // Если не нашли подходящего УСПД, берём просто случайный if (!suitableDADs.Any()) { return(RandomizationProvider.Current.GetInt(0, chromosome.CurrentProject.Equipments.DADs.Length)); } // Иначе берём случайный из подходящих var randomIndex = RandomizationProvider.Current.GetInt(0, suitableDADs.Count()); return(suitableDADs[randomIndex].Index); } catch (Exception ex) { Console.WriteLine("GenerateDADeviceGene failed! {0}", ex.Message); return(0); } }
/// <summary> /// Создать новую топологию - декодировать фенотип хромосомы на базе её текущего генотипа. /// </summary> /// <param name="chromosome">Декодируемая хромосома.</param> public Topology(TopologyChromosome chromosome) { try { Sections = new TopologySection[chromosome.CurrentProject.MCZs.Length]; Pathes = new Dictionary <DataAcquisitionSectionPart, IEnumerable <TopologyPath> >(); DecodeSections(chromosome); GroupDADs(chromosome); DecodePathes(chromosome); } catch (Exception ex) { Console.WriteLine("Topology failed! {0}", ex.Message); } }
/// <summary> /// Генерировать новое случайное значение гена, представляющего устройство учёта и управления. /// Из всех доступных устройств, выбираются только те, которые подходят для данного места учёта и управления. /// Ген является индексом в массиве всех доступных устройств. /// </summary> /// <param name="chromosome">Текущая хромосома.</param> /// <param name="sectionIndex">Индекс секции, для которой генерируется ген.</param> /// <returns>Целочисленное значение случайного гена, соответствующее индексу в массиве доступных устройств.</returns> public static int GenerateDeviceGene(TopologyChromosome chromosome, int sectionIndex) { try { var suitableMCDs = chromosome.CurrentProject.Equipments.MCDs .Select((mcd, index) => new { MCD = mcd, Index = index }) // Запоминаем индекс устройства в массиве всех доступных устройств .Where(q => q.MCD.IsSuitableForMCZ(chromosome.CurrentProject.MCZs[sectionIndex])) // Выбираем только те устройства, которые подходят для места .ToArray(); var randomIndex = RandomizationProvider.Current.GetInt(0, suitableMCDs.Count()); // Выбираем из массива выбранных устройств случайное return(suitableMCDs[randomIndex].Index); } catch (Exception ex) { Console.WriteLine("GenerateMCDevice failed! {0}", ex.Message); return(0); } }
/// <summary> /// Поочерёдно декодировать каждую секцию хромосомы. /// </summary> /// <param name="chromosome">Декодируемая хромосома.</param> protected void DecodeSections(TopologyChromosome chromosome) { try { for (var sectionIndex = 0; sectionIndex < chromosome.Length / TopologyChromosome.GENES_IN_SECTION; sectionIndex++) { if (Sections[sectionIndex] == null) { Sections[sectionIndex] = new TopologySection(); } Sections[sectionIndex].Decode(chromosome, sectionIndex); } } catch (Exception ex) { Console.WriteLine("DecodeSections failed! {0}", ex.Message); } }
/// <summary> /// Сгенерировать новое значение гена секции в зависимости от индекса гена. /// </summary> /// <param name="chromosome">Хромосома, для гена которой предназначено данное значение.</param> /// <param name="geneIndex">Индекс гена в хромосоме.</param> /// <returns>Новое случайное значение гена для хромосомы.</returns> public static int GenerateGeneValue(TopologyChromosome chromosome, int geneIndex) { try { var geneInSectionIndex = GetGeneInSectionIndex(geneIndex); if (geneInSectionIndex >= GeneValueGenerationFuncs.Length) { return(0); } // Вызываем соответствующую функцию для генерации гена return(GeneValueGenerationFuncs[geneInSectionIndex].Invoke(chromosome, GetSectionIndex(geneIndex))); } catch (Exception ex) { Console.WriteLine("EncodeGeneValue failed! {0}", ex.Message); return(0); } }
/// <summary> /// Сгенерировать новый ген, представляющий случайную вершину графа, который находится на выбранном /// месте учёта и управления. Ген является индексом в массиве вершин графа, на которых /// находится данное место учёта и управления. /// </summary> /// <param name="chromosome">Текущая хромосома.</param> /// <param name="sectionIndex">Индекс секции, для которой генерируется ген.</param> /// <returns>Целочисленное значение случайного гена, соответствующее индексу в массиве вершин графа.</returns> public static int GenerateVertexGene(TopologyChromosome chromosome, int sectionIndex) { try { var currentMCZ = chromosome.CurrentProject.MCZs[sectionIndex]; // Текущее место учёта и управления var mczVertices = chromosome.CurrentProject.Graph.VerticesArray .Select((vertex, index) => new { Vertex = vertex, Index = index }) // Запоминаем индекс в массиве каждого места .Where(q => q.Vertex.MCZs.Contains(currentMCZ)).ToArray(); // Берём те вершины графа, где располагается данное место var randomIndex = RandomizationProvider.Current.GetInt(0, mczVertices.Count()); return(mczVertices[randomIndex].Index); } catch (Exception ex) { Console.WriteLine("GenerateMCDVertexGene failed! {0}", ex.Message); return(0); } }
/// <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); } }