public async Task <Responce> GlrTestBestGraphAsync([FromBody] InputGraph input) { var converted = await GraphToMatrixAsync(input); return(await Task.Run(() => { try { // Проверка аргумента на null _ = converted ?? throw new ArgumentNullException(nameof(converted)); IBalanceSolver solver = new AccordBalanceSolver(); var flows = solver.GetFlows(converted.A).ToList(); var globalTest = solver.GlobalTest(converted.X0, converted.A, converted.Measurability, converted.Tolerance); var nodesCount = converted.A.GetLength(0); var glr = solver.GlrTest(converted.X0, converted.A, converted.Measurability, converted.Tolerance, flows, globalTest); var results = new List <GlrOutputFlow>(); while (globalTest >= 1) { // Находим максимальное значение GLR теста в массиве var(i, j) = glr.ArgMax(); // Если у нас не осталось значений больше нуля, то выходим if (glr[i, j] <= 0) { break; } // Добавляем новый поток var aColumn = new double[nodesCount]; aColumn[i] = 1; aColumn[j] = -1; converted.A = converted.A.InsertColumn(aColumn); converted.X0 = converted.X0.Append(0).ToArray(); converted.Measurability = converted.Measurability.Append(0).ToArray(); converted.Tolerance = converted.Tolerance.Append(0).ToArray(); var newFlow = new GlrOutputFlow { Id = Guid.NewGuid().ToString(), Name = "New flow", Number = converted.A.Length - 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; } results.Add(newFlow); // Считаем новое значение глобального теста globalTest = solver.GlobalTest(converted.X0, converted.A, converted.Measurability, converted.Tolerance); // Считаем новое значение GLR теста glr = solver.GlrTest(converted.X0, converted.A, converted.Measurability, converted.Tolerance, flows, globalTest); } return new Responce { Type = "result", Data = results }; } 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 }; } })); }