public static SolutionResult Solve(
            ISolver solver,
            IDictionary <NodeId, Node> nodes,
            InternodeMessagesMap map, List <InternodeMessage> messages,
            List <FixedConstraint> fixedConstraints,
            HashSet <string> allowInstancesMergingForRoles)
        {
            using (var solverModel = solver.CreateModel())
            {
                var msgDecisions = messages
                                   .SelectMany(interNodeMsg => new [] { interNodeMsg.IncomingMessage, interNodeMsg.OutgoingMessage })
                                   .ToDictionary(m => m, m => new MessageDecision(solverModel, m));
                var nodeDecisions = nodes
                                    .ToDictionary(n => n.Key, n => new NodeDecision(solverModel, n.Value));

                AddMessagingConstraints(messages, solverModel, msgDecisions, nodeDecisions);
                SolverUtils.AddFixedConstraints(fixedConstraints, nodeDecisions, solverModel);
                SolverUtils.AddUnboundNodesConstraints(map, nodeDecisions, solverModel);
                SolverUtils.AddIsolatedRoleInstancesConstraints(map, nodeDecisions, allowInstancesMergingForRoles, solverModel);
                AddGoals(solverModel, msgDecisions);

                var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(20));

                var solution = solverModel.Solve(cancellation.Token);

                /*Func<Message, bool> mok = m => messages.Any(im => im.IncomingMessage == m || im.OutgoingMessage == m);
                 * var nodeToMsg = nodes.Values.Select(n => new
                 * {
                 *      Node = n.NodeId.ToString(),
                 *      Msgs =
                 *              string.Join("\n", n.Messages.Where(mok).Select(m => m.Key.ToString()).ToArray())
                 * }).ToArray();*/

                if (solution.IsInfeasible)
                {
                    return(new SolutionResult(cancellation.IsCancellationRequested ? SolutionStatus.Timeout : SolutionStatus.Infeasible, null));
                }

                return(new SolutionResult(
                           SolutionStatus.Solved,
                           nodeDecisions.ToDictionary(
                               d => d.Key,
                               d => (INodeSolution) new NodeSolution(
                                   d.Value.TimeDelta,
                                   GetNonmonotonicTimeDeltasForNode(msgDecisions, d.Value),
                                   d.Value.NrOnConstraints
                                   )
                               )
                           ));
            }
        }
Exemple #2
0
        private void PrintInternodeMessagesMap(InternodeMessagesMap map, StringBuilder log)
        {
            log.AppendLine();
            log.AppendLine("Inter-node messages map:");

            log.Append("  from");
            for (int i = 0; i < map.NodeIndexes.Count; ++i)
            {
                log.AppendFormat("\t#{0}", i);
            }
            log.AppendLine();
            log.AppendLine("to");

            for (int i = 0; i < map.NodeIndexes.Count; ++i)
            {
                log.AppendFormat("#{0}", i);
                for (int j = 0; j < map.NodeIndexes.Count; ++j)
                {
                    if (i != j)
                    {
                        log.AppendFormat("\t{0}", map.Map[j, i]);
                    }
                    else
                    {
                        log.Append("\t-");
                    }
                }
                log.AppendLine();
            }

            if (map.Domains.Count > 0)
            {
                log.AppendLine();
                log.AppendLine("Isolated domains:");
                foreach (var domain in map.Domains)
                {
                    log.AppendFormat("    {0}", string.Join(",", domain.Select(i => i.ToString())));
                    log.AppendLine();
                }
            }

            log.AppendLine();
            foreach (var i in map.NodeIndexes)
            {
                log.AppendFormat("#{0}\t{1}{2}", i.Value, i.Key.NodeId, Environment.NewLine);
            }
        }
Exemple #3
0
        private void PrintFixedConstraints(List <FixedConstraint> fixedConstraints,
                                           Dictionary <NodeId, Node> nodes, InternodeMessagesMap map, StringBuilder log)
        {
            if (fixedConstraints.Count == 0)
            {
                return;
            }

            log.AppendLine();
            log.AppendLine("Known constraints:");

            foreach (var c in fixedConstraints)
            {
                log.AppendFormat("  diff between #{0} and #{1} is {2}{3}",
                                 map.NodeIndexes[nodes[c.Node1]], map.NodeIndexes[nodes[c.Node2]],
                                 c.Value, Environment.NewLine);
            }
        }
        public static ISolutionResult Solve(
            ISolver solver,
            IDictionary <NodeId, Node> nodes, InternodeMessagesMap map, List <InternodeMessage> messages,
            List <FixedConstraint> fixedConstraints, HashSet <string> allowInstancesMergingForRoles)
        {
            using (var solverModel = solver.CreateModel())
            {
                var decisions = nodes.ToDictionary(n => n.Key, n => new NodeDecision(solverModel, n.Value));

                AddMessagingConstraints(messages, decisions, solverModel);
                SolverUtils.AddFixedConstraints(fixedConstraints, decisions, solverModel);
                SolverUtils.AddUnboundNodesConstraints(map, decisions, solverModel);
                SolverUtils.AddIsolatedRoleInstancesConstraints(map, decisions, allowInstancesMergingForRoles, solverModel);
                AddGoals(decisions, solverModel);

                var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(10));

                var solution = solverModel.Solve(cancellation.Token);

                if (solution.IsInfeasible)
                {
                    return(new SolutionResult(cancellation.IsCancellationRequested ? SolutionStatus.Timeout : SolutionStatus.Infeasible));
                }

                return(new SolutionResult(
                           SolutionStatus.Solved,
                           decisions.ToDictionary(
                               d => d.Key,
                               d => (INodeSolution) new NodeSolution(
                                   d.Value.TimeDelta,
                                   new List <TimeDeltaEntry>(),
                                   d.Value.NrOnConstraints
                                   )
                               )
                           ));
            }
        }
Exemple #5
0
        public Task <ISolutionResult> Correlate(
            Dictionary <NodeId, IEnumerable <Messaging.Event> > input,
            List <FixedConstraint> fixedConstraints,
            HashSet <string> allowInstancesMergingForRoles
            )
        {
            var log   = new StringBuilder();
            var nodes = input.ToDictionary(i => i.Key, i => new Node(i.Key));

            var unpairedMessages = new List <A.Message>();

            var internodeMessagesDetectorInput = input.ToDictionary(i => nodes[i.Key], i => i.Value);
            var internodeMessages = internodeMessagesDetector.DiscoverInternodeMessages(internodeMessagesDetectorInput, internodeMessagesLimit, unpairedMessages);

            internodeMessagesDetector.InitializeMessagesLinkedList(nodes.Values);

            var internodeMessagesMap = new InternodeMessagesMap(nodes, internodeMessages);

            ISolutionResult solution;

            if (nodes.Count == 1)
            {
                log.AppendLine("Correlation is not required: only one node is found in the log(s)");
                solution = new SolutionResult(SolutionStatus.Solved,
                                              nodes.ToDictionary(n => n.Key, n => (INodeSolution) new NodeSolution(TimeSpan.Zero, new List <TimeDeltaEntry>(), 0)));
            }
            else if (internodeMessages.Count == 0 && fixedConstraints.Count == 0)
            {
                log.AppendFormat("Correlation is not possible: no inter-node messages found");
                solution = new SolutionResult(SolutionStatus.NoInternodeMessages, new Dictionary <NodeId, INodeSolution>());
            }
            else
            {
                log.AppendFormat("Correlating logs using {0} inter-node messages...{1}", internodeMessages.Count, Environment.NewLine);
                solution = MonotonicTimeSolution.Solve(solver, nodes, internodeMessagesMap, internodeMessages, fixedConstraints, allowInstancesMergingForRoles);

                if (solution.Status != SolutionStatus.Solved)
                {
                    if (solution.Status == SolutionStatus.Timeout)
                    {
                        log.AppendLine("Solver timed out.");
                    }
                    log.AppendLine("Can not correlate logs with the assumption of monotonous time. Trying finding the solution for nonmonotonic time...");

                    for (int currentInternodeMessagesLimit = internodeMessagesLimit; ;)
                    {
                        try
                        {
                            solution = NonmonotonicTimeSolution.Solve(solver, nodes, internodeMessagesMap, internodeMessages, fixedConstraints, allowInstancesMergingForRoles);
                        }
                        catch (UnsolvableModelException ume)
                        {
                            if (ume is ModelTooComplexException)
                            {
                                log.AppendLine("Can not correlate logs because of too many constraints. Msg count = " + currentInternodeMessagesLimit.ToString());
                                currentInternodeMessagesLimit = currentInternodeMessagesLimit * 3 / 4;
                                if (currentInternodeMessagesLimit < nodes.Count)
                                {
                                    throw;
                                }
                                internodeMessages = internodeMessagesDetector.DiscoverInternodeMessages(internodeMessagesDetectorInput, currentInternodeMessagesLimit, new List <A.Message>());
                                continue;
                            }
                            throw;
                        }
                        break;
                    }

                    if (solution.Status != SolutionStatus.Solved &&
                        debugMode)
                    {
                        var problematicNodes = SolutionTroubleshooting.FindProblematicNodesCombinations(solver, nodes, internodeMessages, fixedConstraints, allowInstancesMergingForRoles);
                        if (problematicNodes.Count > 0)
                        {
                            log.AppendLine(SolutionTroubleshooting.LogProblematicNodes(problematicNodes));
                        }
                    }
                }

                if (solution.Status != SolutionStatus.Solved)
                {
                    if (solution.Status == SolutionStatus.Timeout)
                    {
                        log.AppendLine("Solver timed out.");
                    }
                    log.AppendLine("Can not correlate logs :(");
                }
                else
                {
                    log.AppendLine(solution.ToString());
                }
            }

            log.AppendLine();
            log.AppendLine("Details:");
            log.Append(internodeMessagesDetector.Log);

            ReportUnpairedMessages(unpairedMessages, log);

            PrintInternodeMessagesMap(internodeMessagesMap, log);
            PrintFixedConstraints(fixedConstraints, nodes, internodeMessagesMap, log);

            ((SolutionResult)solution).SetLog(log.ToString());

            return(Task.FromResult(solution));
        }
Exemple #6
0
        public static void AddUnboundNodesConstraints(
            InternodeMessagesMap map,
            IDictionary <NodeId, NodeDecision> nodeDecisions,
            Solver.IModel solverModel)
        {
            for (int i = 0; i < map.NodeIndexes.Count; ++i)
            {
                for (int j = 0; j < map.NodeIndexes.Count; ++j)
                {
                    if (i > j && (map.Map[i, j] != 0) != (map.Map[j, i] != 0))                     // if all internode messages between nodes i and j flow in one direction
                    {
                        var n1 = map.Nodes[i];
                        var n2 = map.Nodes[j];

                        // find the least "steep" internode message
                        var message =
                            n1.Messages
                            .Where(m => m.InternodeMessage != null && m.InternodeMessage.GetOppositeMessage(m).Node == n2)
                            .Where(m => !(m.InternodeMessage.OutgoingMessage.Event is ResponselessNetworkMessageEvent))
                            .Select(m => m.InternodeMessage)
                            .Aggregate(new { D = TimeSpan.MaxValue, M = (InternodeMessage)null }, (rslt, m) =>
                        {
                            var d = m.FromTimestamp - m.ToTimestamp;
                            return(d < rslt.D ? new { D = d, M = m } : rslt);
                        }, rslt => rslt.M);
                        if (message == null)
                        {
                            continue;
                        }

                        // add the constraint that emulates instantaneous response to the found message.
                        // this allows finding solution for the two nodes that would be impossible otherwise.
                        var toNodeDecision   = nodeDecisions[message.To.NodeId];
                        var fromNodeDecision = nodeDecisions[message.From.NodeId];
                        solverModel.AddConstraints(
                            SolverUtils.MakeValidSolverIdentifierFromString(message.Id) + "_reverse",
                            new OperatorExpr()
                        {
                            Op   = OperatorExpr.OpType.Get,
                            Left = new OperatorExpr()
                            {
                                Op   = OperatorExpr.OpType.Sub,
                                Left = new TermExpr()
                                {
                                    Variable = fromNodeDecision.Decision
                                },
                                Right = new TermExpr()
                                {
                                    Variable = toNodeDecision.Decision
                                }
                            },
                            Right = new ConstantExpr()
                            {
                                Value = (message.ToTimestamp - message.FromTimestamp).Ticks - 1
                            }
                        }
                            );
                    }
                }
            }
        }
Exemple #7
0
        public static void AddIsolatedRoleInstancesConstraints(
            InternodeMessagesMap map,
            IDictionary <NodeId, NodeDecision> nodeDecisions,
            HashSet <string> allowedRoles,
            Solver.IModel solverModel)
        {
            var handledBadDomains = new HashSet <ISet <int> >();

            foreach (var roleGroup in map.NodeIndexes
                     .Where(x => allowedRoles.Contains(x.Key.NodeId.Role))
                     .GroupBy(x => x.Key.NodeId.Role))
            {
                // domain -> [{node, node index}]  where all nodes are instances of to one role
                var domainGroups = roleGroup
                                   .GroupBy(inst => map.NodeDomains[inst.Value])
                                   .ToDictionary(domainGroup => domainGroup.Key, domainGroup => domainGroup.ToList());

                // skip the role if all instances of it belong to one domain
                if (domainGroups.Count < 2)
                {
                    continue;
                }

                // good is the domain that consists of more than one node
                var goodDomain = domainGroups.FirstOrDefault(d => d.Key.Count > 1);
                if (goodDomain.Key == null)
                {
                    continue;
                }

                foreach (var badDomain in domainGroups
                         .Where(d => d.Key.Count == 1)
                         .Where(d => !handledBadDomains.Contains(d.Key)))
                {
                    var goodDomainDecision = nodeDecisions[goodDomain.Value[0].Key.NodeId];
                    var badDomainDecision  = nodeDecisions[badDomain.Value[0].Key.NodeId];
                    solverModel.AddConstraints(
                        "isolated_domain_link_" + SolverUtils.MakeValidSolverIdentifierFromString(string.Join("_", badDomain.Key)),
                        new OperatorExpr()
                    {
                        Op   = OperatorExpr.OpType.Eq,
                        Left = new OperatorExpr()
                        {
                            Op   = OperatorExpr.OpType.Sub,
                            Left = new TermExpr()
                            {
                                Variable = goodDomainDecision.Decision
                            },
                            Right = new TermExpr()
                            {
                                Variable = badDomainDecision.Decision
                            }
                        },
                        Right = new ConstantExpr()
                        {
                            Value = 0
                        }
                    }
                        );
                    handledBadDomains.Add(badDomain.Key);
                }
            }
            ;
        }