public async Task <Responce> GlrTestAsync([FromBody] InputData input, int maxSubNodesCount = 3, int maxTreeDepth = 5) { return(await Task.Run(() => { try { // Проверка аргумента на null _ = input ?? throw new ArgumentNullException(nameof(input)); IBalanceSolver solver = new MathlabBalanceSolver(); var flows = solver.GetFlows(input.A).ToList(); var nodesCount = input.A.GetLength(0); var root = new MutableEntityTreeNode <Guid, TreeElement>(x => x.Id, new TreeElement()); var currentNode = root; // Пока текущий узел существует while (currentNode != null) { var newA = input.A; var newX0 = input.X0; var newMeasurability = input.Measurability; var newTolerance = input.Tolerance; // Добавляем к исходным данным новые потоки foreach (var(fi, fj) in currentNode.Item.Flows) { var aColumn = new double[nodesCount]; aColumn[fi] = 1; aColumn[fj] = -1; newA = newA.InsertColumn(aColumn); newX0 = newX0.Append(0).ToArray(); newMeasurability = newMeasurability.Append(0).ToArray(); newTolerance = newTolerance.Append(0).ToArray(); } // Текущее значение глобального теста var globalTest = solver.GlobalTest(newX0, newA, newMeasurability, newTolerance); // Таблица GLR теста var glr = solver.GlrTest(newX0, newA, newMeasurability, newTolerance, flows, globalTest); // Поиск следующего максимума var(i, j) = (0, 0); for (var k = 0; k < currentNode.Children.Count + 1; k++) { // Находим максимальное значение GLR теста в массиве (i, j) = glr.ArgMax(); // Если у нас не осталось значений больше нуля, то выходим if (glr[i, j] <= 0) { break; } // Если итерация не последняя if (k != currentNode.Children.Count) { // Сбрасываем значение, чтоб на следующей итерации найти следующий максимум glr[i, j] = 0.0; } } // Проверяем можно ли добавить дочерний узел в дерево if (currentNode.Children.Count < maxSubNodesCount && currentNode.Level < maxTreeDepth && glr[i, j] > 0 && globalTest >= 1) { // Создаем элемент узла var node = new TreeElement(new List <(int, int)>(currentNode.Item.Flows), globalTest - glr[i, j]); node.Flows.Add((i, j)); // Добавляем дочерний элемент и делаем его текущим currentNode = currentNode.AddChild(node); } else { // Поднимаемся выше по дереву currentNode = currentNode.Parent; } } //Находим все листья и выводим их var leafs = root.Where(x => x.IsLeaf); var results = new List <GlrOutput>(); foreach (var leaf in leafs) { var result = new List <GlrOutputFlow>(); var flowsToAdd = new List <Variable>(); foreach (var flow in leaf.Item.Flows) { var(i, j) = flow; // Формируем информацию о потоке var newFlow = new GlrOutputFlow { Id = Guid.NewGuid().ToString(), Name = "New flow", Number = -1, Info = $"{i} -> {j}" }; // Если у нас есть существующий поток, то выводим информацию о нем var existingFlowIdx = flows.FindIndex(x => x.Item1 == i && x.Item2 == j); if (existingFlowIdx != -1) { var(_, _, existingFlow) = flows[existingFlowIdx]; newFlow.Id = input.Guids[existingFlow]; newFlow.Name = input.Names[existingFlow]; newFlow.Number = existingFlow; // Формируем информацию о добавляемом потоке var variable = new Variable { Id = Guid.NewGuid().ToString(), SourceId = input.NodesGuids[i], DestinationId = input.NodesGuids[j], Name = input.Names[existingFlow] + " (additional)", MetrologicRange = new Models.Range { Min = input.LowerMetrologic[existingFlow] - input.X0[existingFlow], Max = input.UpperMetrologic[existingFlow] - input.X0[existingFlow] }, TechnologicRange = new Models.Range { Min = input.LowerTechnologic[existingFlow] - input.X0[existingFlow], Max = input.UpperTechnologic[existingFlow] - input.X0[existingFlow] }, Tolerance = input.Tolerance[existingFlow], IsMeasured = true, VarType = "FLOW" }; flowsToAdd.Add(variable); } // Добавляем поток в выходной список result.Add(newFlow); } results.Add(new GlrOutput { FlowsInfo = result, FlowsToAdd = flowsToAdd, TestValue = leaf.Item.TestValue }); } return new Responce { Type = "result", Data = results.OrderBy(x => x.TestValue) }; } catch (Exception e) { return new Responce { Type = "error", Data = e.Message }; } })); }
public async Task <Responce> GlrTestGraphAsync([FromBody] InputGraph input) { var converted = await GraphToMatrixAsync(input); return(await Task.Run(() => { try { _ = converted ?? throw new ArgumentNullException(nameof(converted)); IBalanceSolver solver = new AccordBalanceSolver(); const int maxSubNodesCount = 3; const int maxTreeDepth = 5; var flows = solver.GetFlows(converted.A).ToList(); var nodesCount = converted.A.GetLength(0); var root = new MutableEntityTreeNode <Guid, TreeElement>(x => x.Id, new TreeElement()); var currentNode = root; while (currentNode != null) { var newA = converted.A; var newX0 = converted.X0; var newMeasurability = converted.Measurability; var newTolerance = converted.Tolerance; foreach (var(fi, fj) in currentNode.Item.Flows) { var aColumn = new double[nodesCount]; aColumn[fi] = 1; aColumn[fj] = -1; newA = newA.InsertColumn(aColumn); newX0 = newX0.Append(0).ToArray(); newMeasurability = newMeasurability.Append(0).ToArray(); newTolerance = newTolerance.Append(0).ToArray(); } var globalTest = solver.GlobalTest(newX0, newA, newMeasurability, newTolerance); var glr = solver.GlrTest(newX0, newA, newMeasurability, newTolerance, flows, globalTest); // Поиск следующего максимума var(i, j) = (0, 0); for (var k = 0; k < currentNode.Children.Count + 1; k++) { (i, j) = glr.ArgMax(); if (glr[i, j] <= 0) { break; } // Если итерация не последняя, сбрасываем значение if (k != currentNode.Children.Count) { glr[i, j] = 0.0; } } // Проверяем можно ли добавить дочерний узел в дерево if (currentNode.Children.Count < maxSubNodesCount && currentNode.Level < maxTreeDepth && glr[i, j] > 0 && globalTest >= 1) { var node = new TreeElement(new List <(int, int)>(currentNode.Item.Flows), globalTest - glr[i, j]); node.Flows.Add((i, j)); currentNode = currentNode.AddChild(node); } else { currentNode = currentNode.Parent; } } //Находим все листья и выводим их var leafs = root.Where(x => x.IsLeaf); var results = new List <GlrOutput>(); foreach (var leaf in leafs) { var result = new List <GlrOutputFlow>(); var flowsToAdd = new List <Variable>(); foreach (var flow in leaf.Item.Flows) { var(i, j) = flow; var newFlow = new GlrOutputFlow { Id = Guid.NewGuid().ToString(), Name = "New flow", Number = -1, Info = $"{i} -> {j}" }; // Если у нас есть существующий поток, то выводим информацию о нем var existingFlowIdx = flows.FindIndex(x => x.Item1 == i && x.Item2 == j); if (existingFlowIdx != -1) { var(_, _, existingFlow) = flows[existingFlowIdx]; newFlow.Id = converted.Guids[existingFlow]; newFlow.Name = converted.Names[existingFlow]; newFlow.Number = existingFlow; // Формируем информацию о добавляемом потоке var variable = new Variable { Id = Guid.NewGuid().ToString(), SourceId = converted.NodesGuids[i], DestinationId = converted.NodesGuids[j], Name = converted.Names[existingFlow] + " (additional)", MetrologicRange = new Models.Range { Min = converted.LowerMetrologic[existingFlow] - converted.X0[existingFlow], Max = converted.UpperMetrologic[existingFlow] - converted.X0[existingFlow] }, TechnologicRange = new Models.Range { Min = converted.LowerTechnologic[existingFlow] - converted.X0[existingFlow], Max = converted.UpperTechnologic[existingFlow] - converted.X0[existingFlow] }, Tolerance = converted.Tolerance[existingFlow], IsMeasured = true, VarType = "FLOW" }; flowsToAdd.Add(variable); } result.Add(newFlow); } results.Add(new GlrOutput { FlowsInfo = result, FlowsToAdd = flowsToAdd, TestValue = leaf.Item.TestValue }); } return new Responce { Type = "result", Data = results.OrderBy(x => x.TestValue) }; } catch (Exception e) { return new Responce { Type = "error", Data = e.Message }; } })); }