public static void showAutomaton(DeterministicFiniteAutomaton G, string name = "Automaton") { string path = $"{name}.html"; var source = new StringBuilder(); source.AppendLine("<!DOCTYPE HTML>"); source.AppendLine("<HTML>"); source.AppendLine("\t<HEAD>"); source.AppendFormat("\t\t<TITLE>{0}</TITLE>", G.Name); source.AppendLine("\t</HEAD>"); source.AppendLine("\t<BODY>"); source.AppendLine("\t\t<script type=\"text/vnd.graphviz\" id=\"cluster\">"); source.AppendLine(G.ToDotCode); source.AppendLine("\t\t</script>"); // //source.AppendLine(@"<script src=""Drawing/viz.js""></script>"); source.AppendLine(@"<script src=""https://github.com/mdaines/viz.js/releases/download/v1.8.0/viz.js""></script>"); source.AppendLine(@" <script> function inspect(s) { return ""<pre>"" + s.replace(/</g, ""<"").replace(/>/g, "">"").replace(/\""/g, """"") + ""</pre>"" } function src(id) { return document.getElementById(id).innerHTML; } function example(id, format, engine) { var result; try { result = Viz(src(id), format, engine); if (format === ""svg"") return result; else return inspect(result); } catch(e) { return inspect(e.toString()); } } document.body.innerHTML += example(""cluster"", ""svg""); </script>"); source.AppendLine("\t</BODY>"); source.AppendLine("</HTML>"); using (var file = new StreamWriter(path)) { file.WriteLine(source.ToString()); } //Process.Start(path); Process.Start(@"cmd.exe ", $@"/c {path}"); Thread.Sleep(1000); }
//gera arquivo de desenho do autômato public static void drawLatexFigure(DeterministicFiniteAutomaton G, string fileName, bool openAfterFinish = true) { string fontSize = "normalsize"; Dictionary <string, DrawingState> statesList = prepare(G); Vector max, min; getMaxAndMin(statesList, out max, out min); foreach (var item in statesList) { var y = item.Value.position.Y - min.Y + Constants.AREA_LIMIT_OFFSET; var x = item.Value.position.X - min.X + Constants.AREA_LIMIT_OFFSET; item.Value.position = new Vector(x, y); } if (!fileName.EndsWith(".txt") && !fileName.EndsWith(".tex")) { fileName += ".txt"; } StreamWriter writer = new StreamWriter(fileName); //cria cabeçalho FigureStream.WriteLatexHeader(writer, max.X + Constants.AREA_LIMIT_OFFSET, max.Y - max.Y + 2 * Constants.AREA_LIMIT_OFFSET); //inverte as cordenas y para desenho no latex foreach (var item in statesList) { item.Value.position = new Vector(item.Value.position.X, -item.Value.position.Y); FigureStream.drawLatexState(writer, item.Value, Constants.STATE_RADIUS, fontSize); } FigureStream.drawFigureLatex(writer, statesList, fontSize); //termina arquivo FigureStream.WriteLatexEnd(writer); writer.Close(); if (openAfterFinish) { System.Diagnostics.Process.Start(fileName); } }
//gera arquivo de desenho do autômato public static void drawSVG(DeterministicFiniteAutomaton G, string fileName, bool openAfterFinish = true) { Dictionary <string, DrawingState> statesList = prepare(G); Vector max, min; getMaxAndMin(statesList, out max, out min); foreach (var item in statesList) { var y = item.Value.position.Y - min.Y + Constants.AREA_LIMIT_OFFSET; var x = item.Value.position.X - min.X + Constants.AREA_LIMIT_OFFSET; item.Value.position = new Vector(x, y); } if (!fileName.EndsWith(".svg")) { fileName += ".svg"; } StreamWriter writer = new StreamWriter(fileName); //cria cabeçalho FigureStream.WriteSVGHeader(writer, max.X + Constants.AREA_LIMIT_OFFSET, max.Y - min.Y + 2 * Constants.AREA_LIMIT_OFFSET); foreach (var item in statesList) { FigureStream.drawSVGState(writer, item.Value, Constants.STATE_RADIUS); } FigureStream.drawFigureSVG(writer, statesList); //termina arquivo FigureStream.WriteSVGEnd(writer); writer.Close(); if (openAfterFinish) { System.Diagnostics.Process.Start(fileName); } }
//Simula a dinamica de força do sistema /// <summary> /// Prepares the specified g. /// </summary> /// <param name="G">The g.</param> /// <returns>Dictionary<System.String, DrawingState>.</returns> private static Dictionary <string, DrawingState> prepare(DeterministicFiniteAutomaton G) { //CRIANDO MÉTODO QUE SERA UTILIZADO PARA O DESENVOLVIMENTO DA BIBLIOTECA var drawingStatesList = new Dictionary <string, DrawingState>(); // lista de estados com cordenadas //Cria uma lista de estados com parametros de posição para serem desenhados foreach (var item in G.States) { var state = new DrawingState(item.ToString(), item.Marking) { initialState = item.Equals(G.InitialState) }; drawingStatesList.Add(item.ToString(), state); } // aloca os estados dentro de um circulo de raio e centro que serão determinados var radius = Constants.SPRING_LENGTH * drawingStatesList.Count; var center = new Vector(radius + Constants.AREA_LIMIT_OFFSET, radius + Constants.AREA_LIMIT_OFFSET); initialConfiguration(drawingStatesList, radius, center); // Atraves da lista de transiçoes associa para cada estado quais sao os estados de origem e qual era o anterior; foreach (var item in G.Transitions) { if (drawingStatesList.TryGetValue(item.Origin.ToString(), out var state)) { var transitionName = item.Trigger + ((item.IsControllableTransition) ? "" : "'"); state.addDestination(drawingStatesList[item.Destination.ToString()], transitionName); } if (drawingStatesList.TryGetValue(item.Destination.ToString(), out state)) { state.addOrigin(drawingStatesList[item.Origin.ToString()]); } } var force = new Vector(); var biggestForce = new Vector(); for (int j = 0; j < Constants.MAX_ITERATIONS; ++j) { force.X = 0; force.Y = 0; foreach (var item in drawingStatesList) { var attractionForce = item.Value.attractionForce(Constants.SPRING_CONSTANT, Constants.SPRING_LENGTH); var repulsionForce = item.Value.repulsionForce(Constants.CONSTANT_OF_REPULSION, drawingStatesList); force = attractionForce + repulsionForce; if (force.Length > biggestForce.Length) { biggestForce = force; } // desloca estado para uma posição melhor if (item.Value.initialState) { continue; } var position = item.Value.position + Constants.DELTA * force; position.X = Max(position.X, Constants.AREA_LIMIT_OFFSET); position.X = Min(position.X, Constants.AREA_LIMIT_OFFSET + 2 * radius); position.Y = Max(position.Y, Constants.AREA_LIMIT_OFFSET); position.Y = Min(position.Y, Constants.AREA_LIMIT_OFFSET + 2 * radius); item.Value.position = position; } if (biggestForce.Length <= Constants.STOP_CRITERION.Length) { break; } } return(drawingStatesList); }
public FJSSP(string file) { try { string[] lines_str = System.IO.File.ReadAllLines(file); var matriz = new List <List <int> >(); for (int i = 0; i < lines_str.Count(); i++) { matriz.Add(new List <int>()); var line = lines_str[i].Split(' '); for (int j = 0; j < line.Count(); j++) { if (line[j] != "") { int.TryParse(line[j], out int aux); matriz[i].Add(aux); } } } var jobs = matriz[0][0]; var job_names = new string[jobs]; for (int i = 1; i <= jobs; i++) { job_names[i - 1] = $"j{i}"; } var maquinas = matriz[0][1]; var maq_names = new string[maquinas]; for (int i = 1; i <= maquinas; i++) { maq_names[i - 1] = $"m{i}"; } var op = 0; for (int i = 1; i < matriz.Count(); i++) { op += matriz[i][0]; } Depth = op * 2; var states_maq = new Dictionary <int, State>(); states_maq[0] = new State($"s{0}", Marking.Marked); states_maq[1] = new State($"s{1}", Marking.Unmarked); states_maq[2] = new State($"s{2}", Marking.Unmarked); List <Transition> transitions_jobs = new List <Transition>(); List <List <Transition> > transitions_maq = new List <List <Transition> >(); for (int i = 0; i < maquinas; i++) { transitions_maq.Add(new List <Transition>()); } Dictionary <string, DFA> DFA_jobs = new Dictionary <string, DFA>(); Dictionary <string, DFA> DFA_maq = new Dictionary <string, DFA>(); List <int> next = new List <int>(); List <int> atual = new List <int> { }; List <int> anterior = atual.ToList(); for (int i = 1; i < jobs + 1; i++) // cada job { atual.Clear(); anterior.Clear(); int idx = 1; for (int j = 1; j < matriz[i][0] + 1; j++) // cada operação { for (int k = 0; k < matriz[i][idx]; k++) // cada máquina { if (j != matriz[i][0]) // não é a última operação { if (anterior.Count == 0) { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{0}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[0], e.Last(), states_maq[1])); // inclui evento a na maq de 0 para 1 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{0}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Unmarked))); // inclui evento b no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[2])); // inclui evento b na maq de 1 para 2 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } else if (anterior.Count == 1) { if (matriz[i][idx + (2 * k) + 1] == anterior[0]) // se máquina atual é igual a anterior { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[1])); // inclui evento a na maq de 2 para 1 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Unmarked))); // inclui evento b no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[2])); // inclui evento b na maq de 1 para 2 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } else { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[0], e.Last(), states_maq[1])); // inclui evento a na maq de 0 para 1 transitions_maq[anterior[0] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[0])); // inclui evento a na maq anterior de 2 para 0 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Unmarked))); // inclui evento b no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[2])); // inclui evento b na maq de 1 para 2 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } } else { for (int m = 0; m < anterior.Count; m++) // para cada máquina que processa a operação anterior { if (matriz[i][idx + (2 * k) + 1] == anterior[m]) // se máquina atual é igual a anterior { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[1])); // inclui evento a na maq de 2 para 1 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Unmarked))); // inclui evento b no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[2])); // inclui evento b na maq de 1 para 2 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } else { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[0], e.Last(), states_maq[1])); // inclui evento a na maq de 0 para 1 transitions_maq[anterior[m] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[0])); // inclui evento a na maq anterior de 2 para 0 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Unmarked))); // inclui evento b no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[2])); // inclui evento b na maq de 1 para 2 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } } } } else { if (anterior.Count == 1) { if (matriz[i][idx + (2 * k) + 1] == anterior[0]) // se máquina atual é igual a anterior { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[1])); // inclui evento a na maq de 2 para 1 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento b no job transitions_jobs.Add(new Transition(new State($"s{2 * j}.{0}", Marking.Marked), new Event("e", Controllability.Uncontrollable), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento e no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[0])); // inclui evento b na maq de 1 para 0 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } else { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[0], e.Last(), states_maq[1])); // inclui evento a na maq de 0 para 1 transitions_maq[anterior[0] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[0])); // inclui evento a na maq anterior de 2 para 0 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[0]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento b no job transitions_jobs.Add(new Transition(new State($"s{2 * j}.{0}", Marking.Marked), new Event("e", Controllability.Uncontrollable), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento e no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[0])); // inclui evento b na maq de 1 para 0 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } } else { for (int m = 0; m < anterior.Count; m++) // para cada máquina que processa a operação anterior { if (matriz[i][idx + (2 * k) + 1] == anterior[m]) // se máquina atual é igual a anterior { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[1])); // inclui evento a na maq de 2 para 1 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento b no job transitions_jobs.Add(new Transition(new State($"s{2 * j}.{0}", Marking.Marked), new Event("e", Controllability.Uncontrollable), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento e no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[0])); // inclui evento b na maq de 1 para 0 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } else { e.Add(new Event($"a{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Controllable)); // cria evento a[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * (j - 1)}.{0}", Marking.Unmarked), e.Last(), new State($"s{2 * j - 1}.{k}", Marking.Unmarked))); // inclui evento a no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[0], e.Last(), states_maq[1])); // inclui evento a na maq de 0 para 1 transitions_maq[anterior[0] - 1].Add(new Transition(states_maq[2], e.Last(), states_maq[0])); // inclui evento a na maq anterior de 2 para 0 time.Add(e.Last(), matriz[i][idx + (2 * k) + 2]); e.Add(new Event($"b{i}{j}{matriz[i][idx + (2 * k) + 1]}{anterior[m]}", Controllability.Uncontrollable)); // cria evento b[job,op,maq,orig] transitions_jobs.Add(new Transition(new State($"s{2 * j - 1}.{k}", Marking.Unmarked), e.Last(), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento b no job transitions_jobs.Add(new Transition(new State($"s{2 * j}.{0}", Marking.Marked), new Event("e", Controllability.Uncontrollable), new State($"s{2 * j}.{0}", Marking.Marked))); // inclui evento e no job transitions_maq[matriz[i][idx + (2 * k) + 1] - 1].Add(new Transition(states_maq[1], e.Last(), states_maq[0])); // inclui evento b na maq de 1 para 0 atual.Add(matriz[i][idx + (2 * k) + 1]); // inclui máquina atual } } } } } idx = idx + matriz[i][idx] * 2 + 1; atual = atual.Distinct().ToList(); anterior = atual.ToList(); atual.Clear(); } DFA_jobs.Add(job_names[i - 1], new DFA(transitions_jobs, new State($"s{0}.{0}", Marking.Unmarked), job_names[i - 1])); transitions_jobs.Clear(); } e.Add(new Event("e", Controllability.Uncontrollable)); for (int i = 0; i < transitions_maq.Count(); i++) { transitions_maq[i].Add(new Transition(states_maq[0], new Event("e", Controllability.Uncontrollable), states_maq[0])); DFA_maq.Add(maq_names[i], new DFA(transitions_maq[i], states_maq[0], maq_names[i])); } Supervisor = DFA.MonolithicSupervisor(DFA_jobs.Values, DFA_maq.Values, true); e = e.Distinct().ToList(); } catch (Exception erro) { Console.WriteLine("Erro: " + erro.Message); } }
/// <summary> /// Observers the property verify. /// </summary> /// <param name="G">The g.</param> /// <param name="relevantArray">The relevant array.</param> /// <param name="Vg">The vg.</param> /// <param name="returnOnDead">if set to <c>true</c> [return on dead].</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> public static bool ObserverPropertyVerify(this DeterministicFiniteAutomaton G, AbstractEvent[] relevantArray, out NondeterministicFiniteAutomaton Vg, bool returnOnDead = true) { var tau = new Event("Tau", Controllability.Controllable); var dead = new State("DEAD", Marking.Marked); bool findDead = false; var relevant = new HashSet <AbstractEvent>(relevantArray) { tau }; var irrelevant = new HashSet <AbstractEvent>(G.Events.Except(relevant)); var transitionsAux = G.Transitions.Union(G.MarkedStates.Select(q => (Transition)(q, tau, q))).ToList(); var M = StronglyConnectedComponentsAutomaton((transitionsAux, G.InitialState), irrelevant); var transitions = M.transitions.GroupBy(t => t.Origin).ToDictionary(g => g.Key, g => g.ToArray()); var Q = new HashSet <(AbstractState, AbstractState)>(); var Qt = new HashSet <(AbstractState, AbstractState)>() { (M.initial, M.initial) }; var vgTransitions = new HashSet <Transition>(); //Vg = (VgTransitions, G.InitialState); while (Qt.Except(Q).Any()) { var Qtemp = new HashSet <(AbstractState, AbstractState)>(); foreach (var q in Qt.Except(Q)) { Q.Add(q); var(q1, q2) = q; var origin = q1 == q2 ? q1 : (new[] { q1, q2 }).OrderBy(qq => qq.ToString()) .Aggregate((a, b) => a.MergeWith(b)); var Enq1 = new HashSet <AbstractEvent>(transitions.ContainsKey(q1) ? transitions[q1].Select(t => t.Trigger) : new AbstractEvent[0]).Distinct(); var Enq2 = new HashSet <AbstractEvent>(transitions.ContainsKey(q2) ? transitions[q2].Select(t => t.Trigger) : new AbstractEvent[0]).Distinct(); foreach (var sigma in Enq1.Union(Enq2)) { if (relevant.Contains(sigma)) { if (Enq1.Contains(sigma) && Enq2.Contains(sigma)) { var d1s = transitions[q1].Where(t => t.Trigger == sigma).Select(t => t.Destination); var d2s = transitions[q2].Where(t => t.Trigger == sigma).Select(t => t.Destination); foreach (var d2 in d2s) { foreach (var d1 in d1s) { var destination = d1 == d2 ? d1 : (new[] { d1, d2 }).OrderBy(qq => qq.ToString()) .Aggregate((a, b) => a.MergeWith(b)); Qtemp.Add((d1, d2)); vgTransitions.Add((origin, sigma, destination)); } } } else if ((Enq1.Contains(sigma) && !Enq2.Intersect(irrelevant).Any()) || (Enq2.Contains(sigma) && !Enq1.Intersect(irrelevant).Any())) { Qtemp.Add((dead, dead)); vgTransitions.Add((origin, sigma, dead)); } } else { if (Enq1.Contains(sigma)) { var d1s = transitions[q1].Where(t => t.Trigger == sigma).Select(t => t.Destination); foreach (var d1 in d1s) { var destination = d1 == q2 ? d1 : (new[] { d1, q2 }).OrderBy(qq => qq.ToString()) .Aggregate((a, b) => a.MergeWith(b)); Qtemp.Add((d1, q2)); vgTransitions.Add((origin, sigma, destination)); } } if (Enq2.Contains(sigma)) { var d2s = transitions[q2].Where(t => t.Trigger == sigma).Select(t => t.Destination); foreach (var d2 in d2s) { var destination = q1 == d2 ? q1 : (new[] { q1, d2 }).OrderBy(qq => qq.ToString()) .Aggregate((a, b) => a.MergeWith(b)); Qtemp.Add((q1, d2)); vgTransitions.Add((origin, sigma, destination)); } } } } } Qt.UnionWith(Qtemp); if (Qtemp.Contains((dead, dead))) { if (returnOnDead) { Vg = new NondeterministicFiniteAutomaton(vgTransitions, G.InitialState, $"OBS({G})"); return(false); } else { findDead = true; } } } Vg = new NondeterministicFiniteAutomaton(vgTransitions, G.InitialState, $"OBS({G})"); return(!findDead); }
/// <summary> /// Observers the property search. /// </summary> /// <param name="G">The g.</param> /// <param name="relevantArray">The relevant array.</param> /// <returns>NondeterministicFiniteAutomaton.</returns> public static NondeterministicFiniteAutomaton ObserverPropertySearch(this DeterministicFiniteAutomaton G, AbstractEvent[] relevantArray) { var tau = new Event("Tau", Controllability.Controllable); var dead = new State("DEAD", Marking.Marked); var relevant = new HashSet <AbstractEvent>(relevantArray) { tau }; var irrelevant = new HashSet <AbstractEvent>(G.Events.Except(relevant)); var transitionsAux = G.Transitions.Select(t => (Transition)(t.Origin.Flatten, t.Trigger, t.Destination.Flatten)) .Union(G.MarkedStates.Select(q => (Transition)(q, tau, q))).ToList(); int renameIdx = 1; while (true) { var M = StronglyConnectedComponentsAutomaton((transitionsAux, G.InitialState), irrelevant); var hasDead = FindDead(M, relevant, irrelevant, dead, out HashSet <((AbstractState q1, AbstractState q2) o, AbstractEvent t, (AbstractState q1, AbstractState q2) d)> VgTransitions); if (!hasDead) { return(new NondeterministicFiniteAutomaton(VgTransitions.Where(t => string.CompareOrdinal(t.o.q1.ToString(), t.o.q2.ToString()) >= 0 && string.CompareOrdinal(t.d.q1.ToString(), t.d.q2.ToString()) >= 0).Select( t => { var origin = t.o.q1 == t.o.q2 ? t.o.q1 : t.o.q1.MergeWith(t.o.q2); var destination = t.d.q1 == t.d.q2 ? t.d.q1 : t.d.q1.MergeWith(t.d.q2); return new Transition(origin, t.t, destination); }), M.initial, $"OBS({G})")); } var initial = (dead, dead); var frontier = new List <((AbstractState q1, AbstractState q2) o, AbstractEvent t, (AbstractState q1, AbstractState q2) d)>(); frontier.AddRange(VgTransitions.Where(t => t.d == initial)); while (frontier.All(t => t.o.q1 != t.o.q2)) { var newFrontier = new List <((AbstractState q1, AbstractState q2) o, AbstractEvent t, (AbstractState q1, AbstractState q2) d)>(); foreach (var t2 in frontier) { newFrontier.AddRange(VgTransitions.Where(t => t.d == t2.o && t.d != t.o)); } frontier = newFrontier; } var(o, _, _) = frontier.First(t => t.o.q1 == t.o.q2); foreach (var q in o.q1.S) { var trans = transitionsAux.Where(t => t.Origin == q && !relevant.Contains(t.Trigger)); if (!trans.Any()) { continue; } var removeTrans = trans.First(); var originalEvent = removeTrans.Trigger; var renamedEvent = new Event($"{originalEvent}'_{renameIdx++}", originalEvent.Controllability); relevant.Add(renamedEvent); transitionsAux.Remove(removeTrans); transitionsAux.Add(new Transition(removeTrans.Origin, renamedEvent, removeTrans.Destination)); break; } } }