public static ProcedureFunctionChart CreateLoopTestPfc() { ProcedureFunctionChart pfc = new ProcedureFunctionChart(new Highpoint.Sage.SimCore.Model("Test model", Guid.NewGuid()), "SFC 1"); #region Create Nodes A = pfc.CreateStep("Step_A", "", Guid.NewGuid()); B = pfc.CreateStep("Step_B", "", Guid.NewGuid()); C = pfc.CreateStep("Step_C", "", Guid.NewGuid()); nA = (IPfcNode)A; nB = (IPfcNode)B; nC = (IPfcNode)C; #endregion Create Nodes #region Create Structure pfc.Bind(nA, nB); pfc.Bind(nB, nC); pfc.Bind(nB, nB); #endregion Create Structure return(pfc); }
private int OnProcessingSequence(IPfcNode node1, IPfcNode node2) { // Must process parallel convergences last. InputRole ir1 = GetValidationData(node1).InputRole; InputRole ir2 = GetValidationData(node2).InputRole; if (ir1 == InputRole.ParallelConvergence && ir2 != InputRole.ParallelConvergence) { return(1); } if (ir1 != InputRole.ParallelConvergence && ir2 == InputRole.ParallelConvergence) { return(-1); } if (Node1DependsOnNode2(node1, node2)) { return(1); } else if (Node1DependsOnNode2(node2, node1)) { return(-1); } else { return(-Comparer.Default.Compare(node2.GraphOrdinal, node1.GraphOrdinal)); } }
/// <summary> /// Determines whether the specified element is the last element on a path. That is, if deletion of this /// element (and its preceding and following links) would not leave dead-end nodes in the graph, it is considered /// to be the last element in the path. /// </summary> /// <param name="element">The specified element.</param> /// <returns> /// <c>true</c> if the specified element is the last element on a path; otherwise, <c>false</c>. /// </returns> public static bool IsLastElementOnPath(IPfcElement element) { if (element.ElementType.Equals(PfcElementType.Link)) { IPfcNode pre = ((IPfcLinkElement)element).Predecessor; if (pre.SuccessorNodes.Count == 1) { return(false); } IPfcNode post = ((IPfcLinkElement)element).Successor; if (post.PredecessorNodes.Count == 1) { return(false); } } else { foreach (IPfcNode pre in ((IPfcNode)element).PredecessorNodes) { if (pre.SuccessorNodes.Count == 1) { return(false); } } foreach (IPfcNode post in ((IPfcNode)element).SuccessorNodes) { if (post.PredecessorNodes.Count == 1) { return(false); } } } return(true); }
public PfcValidationError(string name, string narrative, IPfcNode subject) { m_target = null; m_name = name; m_narrative = narrative; m_subject = subject; }
/// <summary> /// Gets the primary path forward from the provided starting point node. The primary path is /// the path that is comprised of all of the highest-priority links out of each node encountered. /// </summary> /// <param name="startPoint">The starting point.</param> /// <param name="stepsOnly">if set to <c>true</c> it returns steps only. Otherwise, it returns all nodes.</param> /// <returns>The primary path.</returns> public static List <IPfcNode> GetPrimaryPath(IPfcNode startPoint, bool stepsOnly) { List <IPfcNode> retval = new List <IPfcNode>(); IPfcNode cursor = startPoint; while (true) { if (retval.Contains(cursor)) { int firstElementInLoop = retval.IndexOf(cursor); ArrayList loopers = new ArrayList(); for (int i = firstElementInLoop; i < retval.Count; i++) { loopers.Add(retval[i]); } string looperString = StringOperations.ToCommasAndAndedList(loopers); throw new ApplicationException("Primary path contains a loop, which consists of " + looperString + "!"); } if (!stepsOnly || (cursor.ElementType.Equals(PfcElementType.Step))) { retval.Add(cursor); } if (cursor.Successors.Count == 0) { break; } cursor = cursor.SuccessorNodes[0]; } return(retval); }
private bool ProcessParallelConvergence(IPfcNode node) { // Only run it if it's the last encounter of a parallel convergence. if (GetValidationData(node).DequeueCount == node.PredecessorNodes.Count()) { if (m_diagnostics) { Console.WriteLine("\tProcessing closure of {0}.", node.Name); } // To test parallel convergence into a target node, find the divergence node, and then // from that point, all parallel, and at least one of every set of serially divergent // paths, must contain the target node. If not all of the serially-divergent paths does, // then we will catch that in the serial convergence handler. UpdateClosureToken(node as IPfcTransitionNode); return(true); } else { if (m_diagnostics) { Console.WriteLine("\tNot processing {0} further - we'll encounter it again.", node.Name); } return(false); } }
private void BuildDependencies(IPfcNode node, Stack <IPfcLinkElement> stack) { foreach (IPfcLinkElement outbound in node.Successors) { if (!stack.Contains(outbound)) { LinkValidationData lvd = GetValidationData(outbound); if (lvd.NodesBelow == null) { stack.Push(outbound); BuildDependencies(outbound.Successor, stack); stack.Pop(); lvd.NodesBelow = new bool[m_maxGraphOrdinal + 1]; lvd.NodesBelow[outbound.Successor.GraphOrdinal] = true; foreach (IPfcLinkElement succOutboundLink in outbound.Successor.Successors) { LinkValidationData lvSuccLink = GetValidationData(succOutboundLink); if (lvSuccLink.NodesBelow != null) { for (int i = 0; i < m_maxGraphOrdinal + 1; i++) { lvd.NodesBelow[i] |= lvSuccLink.NodesBelow[i]; } } } } } } }
/// <summary> /// Detaches this link from its predecessor and successor. /// </summary> public void Detach() { Predecessor.Successors.Remove(this); m_predecessor = null; Successor.Predecessors.Remove(this); m_successor = null; }
public ValidationToken(IPfcNode origin) { m_origin = origin; Name = string.Format("Token_{0}", _nToken++); IsSelfReferential = true; // Defines a behavior in the underlying TreeNode. m_openAlternatives = 1; }
public void Test_InsertStepAndTransition() { Model model = new Model("SFC Test 1"); ProcedureFunctionChart pfc = new ProcedureFunctionChart(model, "SFC 1", "", Guid.NewGuid()); IPfcStepNode t0 = pfc.CreateStep("START", "", Guid.Empty); IPfcStepNode t1 = pfc.CreateStep("FINISH", "", Guid.Empty); pfc.Bind(t0, t1); string structureString = PfcDiagnostics.GetStructure(pfc); Console.WriteLine("Structure is \r\n" + structureString); // Get reference to old successor IPfcNode pfcNode = pfc.Nodes["T_000"]; IPfcNode oldSuccessorNode = pfcNode.SuccessorNodes[0]; // Add the step IPfcStepNode newStep = pfc.CreateStep("STEP_1", "", Guid.Empty); IPfcTransitionNode newTrans = pfc.CreateTransition(); // We are adding a step following a transition - binding is from selectedTrans-newStep-newTrans-oldSuccessorStep pfc.Bind(pfcNode, newStep); pfc.Bind(newStep, newTrans); pfc.Bind(newTrans, oldSuccessorNode); // Disconnect old successor pfc.Unbind(pfcNode, oldSuccessorNode); structureString = PfcDiagnostics.GetStructure(pfc); Console.WriteLine("Structure is \r\n" + structureString); Assert.IsTrue(structureString.Equals("{START-->[L_000(SFC 1.Root)]-->T_000}\r\n{T_000-->[L_002(SFC 1.Root)]-->STEP_1}\r\n{STEP_1-->[L_003(SFC 1.Root)]-->T_001}\r\n{T_001-->[L_004(SFC 1.Root)]-->FINISH}\r\n")); }
/// <summary> /// Determines whether all backward paths from 'from' contain the node 'target.' If they do, /// and it is the first such encounter for a specific 'from' then it may be said that target /// is the divergence node for 'from.' /// </summary> /// <param name="from">From.</param> /// <param name="target">The target.</param> /// <returns></returns> private bool AllBackwardPathsContain(IPfcNode from, IPfcNode target) { NodeValidationData nvd = GetValidationData(from); if (nvd.IsInPath == null) { if (!from.PredecessorNodes.Any()) { nvd.IsInPath = false; } else if (from == target) { nvd.IsInPath = true; } else { nvd.IsInPath = true; foreach (IPfcNode predecessorNode in from.PredecessorNodes) { if (!AllBackwardPathsContain(predecessorNode, target)) { nvd.IsInPath = false; break; } } } } return(nvd.IsInPath.Value); }
private bool AllForwardPathsContain(IPfcNode from, IPfcNode target, Stack <IPfcNode> path) { NodeValidationData nvd = GetValidationData(from); if (nvd.IsInPath == null) { if (from.SuccessorNodes.Count() == 0) { nvd.IsInPath = false; } else if (from == target) { nvd.IsInPath = true; } else { nvd.IsInPath = true; foreach (IPfcNode succ in from.SuccessorNodes) { if (!AllForwardPathsContain(succ, target, path)) { nvd.IsInPath = false; break; } } } } return(nvd.IsInPath.Value); }
/// <summary> /// Gets the primary path forward from the provided starting point node. The primary path is /// the path that is comprised on all of the highest-priority links out of each node encountered. /// This path consists of /// </summary> /// <param name="startPoint">The starting point.</param> /// <param name="stepsOnly">if set to <c>true</c> it returns steps only. Otherwise, it returns all nodes.</param> /// <returns>The primary path as a string.</returns> public static string GetPrimaryPathAsString(IPfcNode startPoint, bool stepsOnly) { List <IPfcNode> primaryPathList = GetPrimaryPath(startPoint, stepsOnly); string primaryPath = StringOperations.ToCommasAndAndedListOfNames <IPfcNode>(primaryPathList); return(primaryPath); }
private void Reduce() { int count = 0; bool success = false; do { success = false; foreach (IPfcNode node in m_pfc.Nodes) { if ( node.PredecessorNodes.Count == 1 && node.SuccessorNodes.Count == 1 && node.SuccessorNodes[0].PredecessorNodes.Count == 1 && node.SuccessorNodes[0].SuccessorNodes.Count == 1 && ( node.PredecessorNodes[0].SuccessorNodes.Count == 1 || node.SuccessorNodes[0].SuccessorNodes[0].PredecessorNodes.Count == 1) ) { IPfcNode target1 = node; IPfcNode target2 = node.SuccessorNodes[0]; IPfcNode from = node.PredecessorNodes[0]; IPfcNode to = node.SuccessorNodes[0].SuccessorNodes[0]; m_pfc.Bind(from, to); target1.Predecessors[0].Detach(); target1.Successors[0].Detach(); target2.Successors[0].Detach(); success = true; count += 2; } } } while (success); }
//private bool AllBackwardPathsContain(IPfcNode from, IPfcNode target, Stack<IPfcNode> path) { // if (from.PredecessorNodes.Count() == 0) { // return false; // } else if (from == target) { // return true; // } else { // foreach (IPfcNode pred in from.PredecessorNodes) { // if (!path.Contains(pred)) { // path.Push(pred); // if (!AllBackwardPathsContain(pred, target, path)) // return false; // path.Pop(); // } // } // return true; // } //} private IPfcNode DivergenceNodeFor(IPfcNode closure) { NodeValidationData nvd = GetValidationData(closure); //if (nvd.DivergenceNode != null) // return nvd.DivergenceNode; List <IPfcNode> possibles = new List <IPfcNode>(); foreach (IPfcTransitionNode trans in m_pfc.Transitions) { if (Node1DependsOnNode2(closure, trans)) { possibles.Add(trans); } } possibles.Sort(new PfcNode.NodeComparer()); possibles.Reverse(); foreach (IPfcNode possible in possibles) { m_pfc.Nodes.ForEach(n => GetValidationData(n).IsInPath = null); if (AllBackwardPathsContain(closure, possible)) { return(possible); } } return(null); }
private void OnActivationHappened(IPfcNode whoActivated) { Assert.IsTrue(m_nextExpected.Count > 0, "Unexpected activation occurred on " + whoActivated.Name + "."); IPfcNode t = (IPfcNode)m_nextExpected.Dequeue(); Assert.AreEqual(t, whoActivated, "" + whoActivated.Name + " activated, but we were expecting " + t.Name + " to do so. This is an error."); Console.WriteLine("Activation happened with " + t.Name + "."); }
private bool AllForwardPathsContain(IPfcNode from, IPfcNode target) { m_pfc.Nodes.ForEach(n => GetValidationData(n).IsInPath = null); Stack <IPfcNode> path = new Stack <IPfcNode>(); path.Push(from); return(AllForwardPathsContain(from, target, path)); }
/// <summary> /// Gets the divergence node (step or transtion) for the specified convergence node. This assumes /// that outbound paths all diverged at the same node, and will converge at the same node as well. /// </summary> /// <param name="convergenceNode">The convergence node.</param> /// <returns> /// The join node, if the provided node is a convergence node, otherwise null. /// </returns> public static IPfcNode GetDivergenceNodeFor(IPfcNode convergenceNode) { if (convergenceNode.PredecessorNodes.Count < 2) { return(null); } return((IPfcNode)GetDivergenceElementForParallelPath(convergenceNode.PredecessorNodes[0])); }
/// <summary> /// Gets the convergence node (step or transtion) for the specified divergence node. This assumes /// that outbound paths all diverged at the same node, and will converge at the same node as well. /// </summary> /// <param name="divergenceNode">The divergence node.</param> /// <returns>The convergence node, if this node is a divergence node, otherwise null.</returns> public static IPfcNode GetConvergenceNodeFor(IPfcNode divergenceNode) { if (divergenceNode.SuccessorNodes.Count < 2) { return(null); } return((IPfcNode)GetJoinNodeForParallelPath(divergenceNode.SuccessorNodes[0])); }
public static void Detach(IPfcNode node) { NodeValidationData vd = node.UserData as NodeValidationData; if (vd != null) { node.UserData = vd.m_userData; } }
public static Dictionary <IPfcNode, int> GetNodeDepths(ProcedureFunctionChart pfc) { Dictionary <IPfcNode, int> depths = new Dictionary <IPfcNode, int>(); //List<IPfcStepNode> nodes = //Debug.Assert( nodes.Count == 1, "A PFC was passed into PFCAnalyst.GetNodeDepths(...) that had " + nodes.Count + " finish steps. This is illegal." ); IPfcNode node = pfc.GetFinishTransition( ); GetDepth(node, ref depths); return(depths); }
/// <summary> /// Gets the link that connects this node to a successor node. Returns null if there is no such link. /// </summary> /// <param name="successorNode">The successor.</param> /// <returns></returns> public IPfcLinkElement GetLinkForSuccessorNode(IPfcNode successorNode) { IPfcLinkElement retval = null; m_successors.ForEach(delegate(IPfcLinkElement le) { if (le.Successor == successorNode) { retval = le; } }); return(retval); }
/// <summary> /// Gets the link that connects this node to a predecessor node. Returns null if there is no such link. /// </summary> /// <param name="predecessorNode">The predecessor.</param> /// <returns></returns> public IPfcLinkElement GetLinkForPredecessorNode(IPfcNode predecessorNode) { IPfcLinkElement retval = null; m_predecessors.ForEach(delegate(IPfcLinkElement le) { if (le.Predecessor == predecessorNode) { retval = le; } }); return(retval); }
private void ProcessSerialDivergence(IPfcNode node) { ValidationToken nodeVt = GetValidationData(node).ValidationToken; foreach (IPfcNode successor in node.SuccessorNodes) { nodeVt.IncrementAlternatePathsOpen(); Enqueue(node, successor, nodeVt); } nodeVt.DecrementAlternatePathsOpen(); //added 1 per child, subtract 1 overall. Thus 1 split to 4 yields 4 alt. }
/// <summary> /// Dequeues and sets up for evaluation, the active path. /// </summary> /// <returns>IPfcNode.</returns> private IPfcNode Dequeue() { List <QueueData> tmp = new List <QueueData>(m_activePath); tmp.Sort(OnProcessingSequence); m_activePath.Clear(); tmp.ForEach(n => m_activePath.Enqueue(n)); QueueData qd = m_activePath.Dequeue(); IPfcNode retval = qd.To; return(retval); }
public static ProcedureFunctionChart CreateTestPfc5() { // Flip-flop pattern. ProcedureFunctionChart pfc = new ProcedureFunctionChart(new Highpoint.Sage.SimCore.Model("Test model", Guid.NewGuid()), "SFC 1"); #region Create Nodes char name = 'A'; A = pfc.CreateStep("Step_" + (name++), "", NextGuid()); B = pfc.CreateStep("Step_" + (name++), "", NextGuid()); C = pfc.CreateStep("Step_" + (name++), "", NextGuid()); D = pfc.CreateStep("Step_" + (name++), "", NextGuid()); E = pfc.CreateStep("Step_" + (name++), "", NextGuid()); F = pfc.CreateStep("Step_" + (name++), "", NextGuid()); nA = (IPfcNode)A; nB = (IPfcNode)B; nC = (IPfcNode)C; nD = (IPfcNode)D; nE = (IPfcNode)E; nF = (IPfcNode)F; #endregion Create Nodes #region Create Structure pfc.BindParallelDivergent(nA, new IPfcNode[] { nB, nC }); pfc.BindSeriesDivergent(nB, new IPfcNode[] { nD, nE }); pfc.BindSeriesDivergent(nC, new IPfcNode[] { nD, nE }); pfc.BindParallelConvergent(new IPfcNode[] { nD, nE }, nF); PfcLinkElementList links = new PfcLinkElementList(pfc.Links); links.Sort(new Comparison <IPfcLinkElement>(delegate(IPfcLinkElement a, IPfcLinkElement b) { return(Comparer.Default.Compare(a.Name, b.Name)); })); System.Reflection.BindingFlags bf = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance; foreach (IPfcLinkElement link in links) { typeof(PfcElement).GetFields(bf); typeof(PfcElement).GetField("m_guid", bf).SetValue((PfcElement)link, NextGuid()); // Totally cheating. } //pfc.Bind(nD, pfc.Nodes["T_005"]); #endregion Create Structure return(pfc); }
public static bool IsTargetNodeLegal(IPfcNode origin, IPfcNode target) { bool retval = false; IProcedureFunctionChart parent = origin.Parent; // We only evaluate step-to-step links, or transition-to-transition links, // meaning that we must always add a shim node between them. if (origin.ElementType.Equals(target.ElementType)) { if (s_diagnostics) { Console.WriteLine("Before: " + StringOperations.ToCommasAndAndedListOfNames <IPfcNode>(parent.Nodes)); } IPfcLinkElement link1, link2; IPfcNode shimNode; parent.Bind(origin, target, out link1, out shimNode, out link2, false); if (s_diagnostics) { Console.WriteLine("During: " + StringOperations.ToCommasAndAndedListOfNames <IPfcNode>(parent.Nodes)); } PfcValidator validator = new PfcValidator(parent); retval = validator.PfcIsValid(); if (shimNode != null) { parent.Unbind(origin, shimNode, true); parent.Unbind(shimNode, target, true); parent.UpdateStructure(); } else { parent.Unbind(origin, target); } if (s_diagnostics) { Console.WriteLine("After: " + StringOperations.ToCommasAndAndedListOfNames <IPfcNode>(parent.Nodes)); } parent.ElementFactory.Retract(); } else { return(false); } return(retval); }
private void Enqueue(IPfcNode from, IPfcNode node, ValidationToken vt) { NodeValidationData vd = GetValidationData(node); if (vd.InputRole == InputRole.ParallelConvergence) { GetValidationData(from).ValidationToken.DecrementAlternatePathsOpen(); } vd.ValidationToken = vt; m_activePath.Enqueue(new QueueData(from, node)); if (m_diagnostics) { Console.WriteLine("\tEnqueueing {0} with {1} ({2}).", node.Name, vt, vt.AlternatePathsOpen); } }
public static ProcedureFunctionChart CreateTestPfc4() { ProcedureFunctionChart pfc = new ProcedureFunctionChart(new Highpoint.Sage.SimCore.Model("Test model", Guid.NewGuid()), "SFC 1"); #region Create Nodes char name = 'A'; A = pfc.CreateStep("Step_" + (name++), "", NextGuid()); B = pfc.CreateStep("Step_" + (name++), "", NextGuid()); C = pfc.CreateStep("Step_" + (name++), "", NextGuid()); D = pfc.CreateStep("Step_" + (name++), "", NextGuid()); E = pfc.CreateStep("Step_" + (name++), "", NextGuid()); nA = (IPfcNode)A; nB = (IPfcNode)B; nC = (IPfcNode)C; nD = (IPfcNode)D; nE = (IPfcNode)E; #endregion Create Nodes #region Create Structure pfc.Bind(nA, nB); pfc.Bind(nB, nE); pfc.Bind(nA.SuccessorNodes[0], nC); pfc.Bind(nC, nD); pfc.Bind(nD, nE.PredecessorNodes[0]); PfcLinkElementList links = new PfcLinkElementList(pfc.Links); links.Sort(new Comparison <IPfcLinkElement>(delegate(IPfcLinkElement a, IPfcLinkElement b) { return(Comparer.Default.Compare(a.Name, b.Name)); })); System.Reflection.BindingFlags bf = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance; foreach (IPfcLinkElement link in links) { typeof(PfcElement).GetFields(bf); typeof(PfcElement).GetField("m_guid", bf).SetValue((PfcElement)link, NextGuid()); // Totally cheating. } #endregion Create Structure return(pfc); }
private static IPfcNode GetPrevParallelDivergenceNode(IPfcNode origin) { IPfcNode ppdn = GetPrevDivergenceNode(origin); if (ppdn != null) { while (ppdn.ElementType.Equals(PfcElementType.Step) || ppdn.PredecessorNodes.Count == 0) { ppdn = GetPrevDivergenceNode(ppdn); if (ppdn == null) { break; } } } return(ppdn); }