public static void AddFixedConstraints(List <NodesConstraint> fixedConstraints, IDictionary <NodeId, NodeDecision> nodeDecisions, IModel solverModel) { foreach (var constraint in fixedConstraints) { var toNodeDecision = nodeDecisions[constraint.Node1]; var fromNodeDecision = nodeDecisions[constraint.Node2]; solverModel.AddConstraints( SolverUtils.MakeValidSolverIdentifierFromString(string.Format("fixed-diff-{0}-{1}", constraint.Node1, constraint.Node2)), new OperatorExpr() { Op = OperatorExpr.OpType.Eq, Left = new OperatorExpr() { Op = OperatorExpr.OpType.Sub, Left = new TermExpr() { Variable = toNodeDecision.Decision }, Right = new TermExpr() { Variable = fromNodeDecision.Decision }, }, Right = new ConstantExpr() { Value = constraint.Value.Ticks } } ); toNodeDecision.UsedInConstraint(); fromNodeDecision.UsedInConstraint(); } }
private static void AddMessagingConstraints(List <InternodeMessage> messages, IDictionary <NodeId, NodeDecision> nodeDecisions, IModel solverModel) { foreach (var message in messages) { var toNodeDecision = nodeDecisions[message.To.NodeId]; var fromNodeDecision = nodeDecisions[message.From.NodeId]; solverModel.AddConstraints( SolverUtils.MakeValidSolverIdentifierFromString(message.Id), new OperatorExpr() { Op = OperatorExpr.OpType.Get, Left = new OperatorExpr() { Op = OperatorExpr.OpType.Sub, Left = new TermExpr() { Variable = toNodeDecision.Decision, }, Right = new TermExpr() { Variable = fromNodeDecision.Decision, }, }, Right = new ConstantExpr() { Value = (message.FromTimestamp - message.ToTimestamp).Ticks + 1 } } ); toNodeDecision.UsedInConstraint(); fromNodeDecision.UsedInConstraint(); } }
private static void AddMessagingConstraints(List <InternodeMessage> messages, IModel solverModel, Dictionary <Message, MessageDecision> msgDecisions, Dictionary <NodeId, NodeDecision> nodeDecisions) { Func <Message, Expr> getTerm = m => { Expr ret = new TermExpr() { Variable = nodeDecisions[m.Node.NodeId].Decision }; for (; m != null; m = m.Prev) { MessageDecision d; if (msgDecisions.TryGetValue(m, out d)) { ret = new OperatorExpr() { Op = OperatorExpr.OpType.Sub, Left = ret, Right = new TermExpr() { Variable = d.Decision } } } ; } return(ret); }; foreach (var message in messages) { var toNodeDecision = getTerm(message.IncomingMessage); var fromNodeDecision = getTerm(message.OutgoingMessage); solverModel.AddConstraints( SolverUtils.MakeValidSolverIdentifierFromString("MessageConstraint_" + message.Id), new OperatorExpr() { Op = OperatorExpr.OpType.Get, Left = new OperatorExpr() { Op = OperatorExpr.OpType.Sub, Left = toNodeDecision, Right = fromNodeDecision, }, Right = new ConstantExpr() { Value = (message.FromTimestamp - message.ToTimestamp).Ticks + 1 } } ); nodeDecisions[message.IncomingMessage.Node.NodeId].UsedInConstraint(); nodeDecisions[message.OutgoingMessage.Node.NodeId].UsedInConstraint(); } }
public static SolutionResult Solve( ISolver solver, IDictionary <NodeId, Node> nodes, InternodeMessagesMap map, List <InternodeMessage> messages, List <NodesConstraint> 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 => new NodeSolution( d.Value.TimeDelta, GetNonmonotonicTimeDeltasForNode(msgDecisions, d.Value), d.Value.NrOnConstraints ) ) )); } }
public static ISolutionResult Solve( ISolver solver, IDictionary <NodeId, Node> nodes, InternodeMessagesMap map, List <InternodeMessage> messages, List <NodesConstraint> 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 => new NodeSolution( d.Value.TimeDelta, new List <TimeDeltaEntry>(), d.Value.NrOnConstraints ) ) )); } }
public DecisionBase(IModel model, string decisionName) { this.Decision = model.CreateDecision(SolverUtils.MakeValidSolverIdentifierFromString(decisionName)); }
public static void AddUnboundNodesConstraints( InternodeMessagesMap map, IDictionary <NodeId, NodeDecision> nodeDecisions, 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 } } ); } } } }
public static void AddIsolatedRoleInstancesConstraints( InternodeMessagesMap map, IDictionary <NodeId, NodeDecision> nodeDecisions, HashSet <string> allowedRoles, 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); } } ; }