/// <summary> /// Tries to perform at most given number of steps of word evaluation. /// </summary> /// <param name="numberOfSteps">if zero, the evaluation continues until it is complete</param> public void Evaluate(int numberOfSteps) { if (!IsConstructionFinished()) { throw new InvalidOperationException("cannot evaluate word when the fsm is not yet completely constructed"); } if (numberOfSteps <= 0) { numberOfSteps = -1; } while (numberOfSteps != 0 && !IsEvaluationFinished()) { // remove single letter var letter = evaluatedWordRemainingFragment[0].ToString(); MachineTransition transition = transitions.FirstOrNull( x => x.InitialStateId == currentState && x.ContainsLetter(letter)); //try //{ // transition = transitions.First(x => x.InitialStateId == currentState && x.ContainsLetter(letter)); //} //catch (InvalidOperationException) //{ // // silent catch, matching transition was not found //} evaluatedWordProcessedFragment = new StringBuilder(evaluatedWordProcessedFragment) .Append(letter).ToString(); evaluatedWordRemainingFragment = evaluatedWordRemainingFragment.Substring(1); previousState = currentState; if (transition == null) { currentState = -1; break; } currentState = transition.ResultingStateId; if (numberOfSteps > 0) { --numberOfSteps; } } }
public void Draw(Canvas canvas, bool constructionMode, IList <RegularExpression> highlightedStates, IList <MachineTransition> highlightedTransitions, bool evaluationMode, int previousState, int currentState, bool evaluationEnded) { if (canvas == null) { throw new ArgumentNullException("canvas"); } canvas.Clear(); double maxX = 0; double maxY = 0; { double startAngle = FindMostFreeAngle(0, true, false, 315); if (constructionMode && highlightedStates.Any(x => states.IndexOf(x) == 0)) { DrawStartArrow(canvas, HighlightedEdgeBrush, HighlightedEdgeBorderBrush, vertices[0], startAngle); } else { DrawStartArrow(canvas, EdgeBrush, EdgeBorderBrush, vertices[0], startAngle); } } string text = String.Empty; for (int i = 0; i < vertices.Count; ++i) { var location = vertices[i]; int transitionIndex = -1; foreach (var transition in transitions) { ++transitionIndex; if (transition.InitialStateId != i) { continue; } var letters = new TextBlock(); letters.Height = TextBlockHeight; //letters.Width = double.NaN; // Auto, goes to 100% letters.Width = transition.Item2.Count * TextBlockHeight; letters.Text = String.Join(" ", transition.Item2); letters.TextAlignment = TextAlignment.Center; Brush edgeBrush = null; Brush edgeBorderBrush = null; Brush edgeLabelBrush = null; if (constructionMode && highlightedTransitions.Any(x => x.InitialStateId == transition.InitialStateId && x.ResultingStateId == transition.ResultingStateId)) { edgeBrush = HighlightedEdgeBrush; edgeBorderBrush = HighlightedEdgeBorderBrush; edgeLabelBrush = HighlightedEdgeLabelBrush; } else if (evaluationMode && transition.InitialStateId == previousState && transition.ResultingStateId == currentState) { edgeBrush = HighlightedEdgeBrush; edgeBorderBrush = HighlightedEdgeBorderBrush; edgeLabelBrush = HighlightedEdgeLabelBrush; } else { edgeBrush = EdgeBrush; edgeBorderBrush = EdgeBorderBrush; edgeLabelBrush = EdgeLabelBrush; } letters.Foreground = edgeLabelBrush; if (transition.Item3 == i) { // loop, i.e. directed edge to self double angle = edges[transition].Item1; DrawLoop(canvas, edgeBrush, edgeBorderBrush, edgeLabelBrush, location, angle); Point translatePoint = new Point(0, 0).MoveTo(angle, LoopHeight); if (angle > 90 && angle <= 270) { angle -= 180; } var rotateTransform = new RotateTransform(angle, letters.Width / 2, TextBlockHeight / 2); var translateTransform = new TranslateTransform(translatePoint.X, translatePoint.Y); var transforms = new TransformGroup(); transforms.Children.Add(rotateTransform); transforms.Children.Add(translateTransform); letters.RenderTransform = transforms; canvas.Add(letters, location.X - letters.Width / 2, location.Y - TextBlockHeight / 2, 0); } else { // normal edge Point endpoint = vertices[transition.Item3]; double angle = edges[transition].Item1 - 90; // double angle = location.Angle(endpoint) - 90; // already got it Point translatePoint; Point middle = new Point((location.X + endpoint.X) / 2, (location.Y + endpoint.Y) / 2); List <Point> intersections = new List <Point>(); if (layoutScore.IntersectingEdges.Count > 0) { // detect intersections with other edges to move label to the longest uninterrupted segment foreach (var intr in layoutScore.IntersectingEdges) { if (intr.Item1 != transitionIndex) { continue; } MachineTransition intersectingTransition = transitions[intr.Item2]; Point p1 = vertices[intersectingTransition.InitialStateId]; Point p2 = vertices[intersectingTransition.ResultingStateId]; Point intersection = location.FindIntersectionAssumingItExists(endpoint, p1, p2); intersections.Add(intersection); } // detect overlapping vertices to move label away from them foreach (var intr in layoutScore.VerticesOnEdges) { // the vertex must be near currently evaluated transition if (intr.Item2 != transitionIndex) { continue; } //double angle = location.Angle(endpoint); // already got it Point intersection = vertices[intr.Item1].MoveTo(angle, intr.Item3); if (intersection.DistanceToLine(location, endpoint) > intr.Item3) { intersection = vertices[intr.Item1].MoveTo(angle + 180, intr.Item3); } intersections.Add(intersection); } if (intersections.Count > 0) { intersections.Add(location.MoveTo(endpoint, StateEllipseDiameter / 2)); intersections.Add(endpoint.MoveTo(location, StateEllipseDiameter / 2)); intersections.Sort((a, b) => a.X.CompareTo(b.X)); } } if (intersections.Count > 0) { var intersectionDistances = intersections.Zip(intersections.Skip(1), (x, y) => y.Distance(x)).ToArray(); //Console.Out.WriteLine(String.Join("; ", intersectionDistances)); // find the best position for the label // i.e. the longest fragment without intersections int index = intersectionDistances.IndexOfMax(); double max = intersectionDistances[index]; middle = intersections[index].MoveTo(intersections[index + 1], max / 2); //DrawDot(canvas, Brushes.Red, middle); } //TODO: take bent edges into account (i.e. case of two transitions: q1->q2 and q2->q1) // because in such cases labels are sometimes too close to the edges they belong to if (transitions.Any(x => x.InitialStateId == transition.ResultingStateId && x.ResultingStateId == transition.InitialStateId)) { if (angle > 90 && angle <= 270) { angle -= 180; translatePoint = new Point(0, 0).MoveTo(angle, TextBlockHeight / 2 + 4); } else { translatePoint = new Point(0, 0).MoveTo(angle, -TextBlockHeight / 2 - 4); } DrawEdge(canvas, edgeBrush, edgeBorderBrush, edgeLabelBrush, location, edges[transition].Item1, endpoint, edges[transition].Item2); } else { DrawEdge(canvas, edgeBrush, edgeBorderBrush, edgeLabelBrush, location, endpoint); if (angle > 90 && angle <= 270) { angle -= 180; } translatePoint = new Point(0, 0).MoveTo(angle, TextBlockHeight / 2 - 2); } var rotateTransform = new RotateTransform(angle, letters.Width / 2, TextBlockHeight / 2); var translateTransform = new TranslateTransform(translatePoint.X, translatePoint.Y); var transforms = new TransformGroup(); transforms.Children.Add(rotateTransform); transforms.Children.Add(translateTransform); letters.RenderTransform = transforms; canvas.Add(letters, middle.X - letters.Width / 2, middle.Y - TextBlockHeight / 2, 0); } } Brush vertexBrush = null; Brush vertexBackgroundBrush = null; Brush vertexLabelBrush = null; if (constructionMode && highlightedStates.Any(x => states.IndexOf(x) == i)) { vertexBrush = HighlightedVertexBrush; vertexBackgroundBrush = HighlightedVertexBackgroundBrush; vertexLabelBrush = HighlightedVertexLabelBrush; } else if (evaluationMode) { if (currentState == i) { if (evaluationEnded) { vertexBrush = VertexBrush; vertexBackgroundBrush = WordAcceptedStateBackgroundBrush; vertexLabelBrush = VertexLabelBrush; } else { vertexBrush = HighlightedVertexBrush; vertexBackgroundBrush = HighlightedVertexBackgroundBrush; vertexLabelBrush = HighlightedVertexLabelBrush; } } else if (previousState == i && currentState == -1) { vertexBrush = VertexBrush; vertexBackgroundBrush = WordRejectedStateBackgroundBrush; vertexLabelBrush = VertexLabelBrush; } else { vertexBrush = VertexBrush; vertexBackgroundBrush = VertexBackgroundBrush; vertexLabelBrush = VertexLabelBrush; } } else { vertexBrush = VertexBrush; vertexBackgroundBrush = VertexBackgroundBrush; vertexLabelBrush = VertexLabelBrush; } DrawState(canvas, vertexBrush, vertexBackgroundBrush, vertexLabelBrush, location, String.Format("q{0}", i), acceptingStates.Any(x => x == states[i])); if (location.X > maxX) { maxX = location.X; } if (location.Y > maxY) { maxY = location.Y; } } canvas.Width = maxX + LayoutOffset; canvas.Height = maxY + LayoutOffset; }
/// <summary> /// Derives next expression from the not-derived-expressions queue. /// </summary> /// <returns>true if any expression was derived during execution of this method</returns> private bool DeriveNextExpression() { if (notDerivedIds.Count == 0) { return(false); } var currentId = notDerivedIds[0]; var current = equivalentStatesGroups[currentId].Value[0]; // .First(x => x.Key == currentId) var alphabet = current.Alphabet; int count = alphabet.Count; if (count > 0) { Thread[] derivationThreads = new Thread[count]; RegularExpression[] derivations = new RegularExpression[count]; #region obsolete manual parallelization /**** * * int processorsCount = count; // TODO: get total number of logical processing units * Semaphore semaphore = new Semaphore(processorsCount, processorsCount); * * // derive in parallel * for (int i = 0; i < count; ++i) * { * Thread t = new Thread(new ParameterizedThreadStart((object obj) => * { * int n = (int)obj; * semaphore.WaitOne(); * derivations[n] = current.Derive(alphabet[n]); * semaphore.Release(); * })); * t.Name = "DerivationThread"; * t.Priority = ThreadPriority.Lowest; * t.SetApartmentState(ApartmentState.STA); * t.Start(i); * derivationThreads[i] = t; * } * * // sync * for (int i = 0; i < count; ++i) * derivationThreads[i].Join(); * ****/ #endregion // derive in parallel if (count > 1) { Parallel.For(0, count, (int n) => { derivations[n] = current.Derive(alphabet[n]); }); } else { derivations[0] = current.Derive(alphabet[0]); } // analyze results in sequence for (int i = 0; i < count; ++i) { var derived = derivations[i]; if (derived == null) { continue; } var letter = alphabet[i]; var derivedId = equivalentStatesGroups.FindIndex(x => x.Value.Any(y => y.Equals(derived))); if (derivedId >= 0) { var foundTransition = transitions.FindIndex(x => x.Item1 == currentId && x.Item3 == derivedId); if (foundTransition >= 0) { transitions[foundTransition].AddLetter(letter); latestTransitions.Add(transitions[foundTransition]); } else { var mt = new MachineTransition(currentId, letter, derivedId); transitions.Add(mt); latestTransitions.Add(mt); } } else { notLabeled.Add(derived); notOptimizedTransitions.Add(new Tuple <int, string, RegularExpression>(currentId, letter, derived)); } } } //foreach (var letter in current.Alphabet) //{ // //if (states.Any(x => x.IsEqual(current))) // // continue; //} notDerivedIds.RemoveAt(0); return(true); }
/// <summary> /// /// </summary> /// <param name="equivalentToExpression"></param> private void ManuallyLabelNextExpression(RegularExpression equivalentToExpression) { RegularExpression labeled = notLabeled[0]; int labeledId = -1; if (equivalentToExpression == null) { labeledId = equivalentStatesGroups.Count; notLabeled.RemoveAt(0); equivalentStatesGroups.Add(new KeyValuePair <int, List <RegularExpression> >(labeledId, new List <RegularExpression>())); equivalentStatesGroups[labeledId].Value.Add(labeled); latestStates.Add(labeled); if (labeled.GeneratesEmptyWord()) { acceptingStatesIds.Add(labeledId); } notDerivedIds.Add(labeledId); } else { foreach (var group in equivalentStatesGroups) { if (!group.Value.Any(x => x.Equals(equivalentToExpression))) { continue; } labeledId = group.Key; break; } if (labeledId < 0 && labeledId >= equivalentStatesGroups.Count) { throw new ArgumentException("must be either null or an expression that is already labeled", "equivalentToExpression"); } equivalentStatesGroups[labeledId].Value.Add(labeled); } if (notOptimizedTransitions == null || notOptimizedTransitions.Count == 0) { return; } var transitionsForOptimization = notOptimizedTransitions.FindAll(x => x.Item3.Equals(labeled)); transitionsForOptimization.ForEach(x => { var foundTransition = transitions.FindIndex(y => y.Item1 == x.Item1 && y.Item3 == labeledId); if (foundTransition >= 0) { // this can happen if more than one transition is optimized in this step transitions[foundTransition].AddLetter(x.Item2); } else { MachineTransition transition = new MachineTransition(x.Item1, x.Item2, labeledId); transitions.Add(transition); latestTransitions.Add(transition); } }); transitionsForOptimization.ForEach(x => notOptimizedTransitions.Remove(x)); }