![]() |
Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Hallo zusammen,
ich habe einen Fahrplan, durch den definiert ist, wo welche Teile in einer Produktion bearbeitet werden dürfen. Dafür werden Quell- und Zielstationen sowie eine Bedingung (nur Gutteile, nur Schlechtteile, ...) festgelegt. Das sieht z.B. so aus (schematisch dargestellt):
Code:
Das bedeutet für obiges Beispiel:
class FahrplanEintrag
{ int QuellStation; // -1 = Keine Vorgeschichte, d.h. ZielStation = Start-Station int ZielStation; int Bedingung; } List<FahrplanEintrag> Fahrplan = new List<FahrplanEintrag>() { new FahrplanEintrag() { QuellStation = -1, ZielStation = 1, Bedingung = 0, // alle Teile }, new FahrplanEintrag() { QuellStation = 1, ZielStation = 2, Bedingung = 1, // nur Gutteile }, new FahrplanEintrag() { QuellStation = 1, ZielStation = 1, Bedingung = 2, // nur Schlechtteile (erneute Bearbeitung in Station 1 zulässig) }, new FahrplanEintrag() { QuellStation = 2, ZielStation = 3, Bedingung = 1, // nur Gutteile }, // ... } In der ZielStation 1 darf jedes Teil bearbeitet werden, das zuvor an keiner Station bearbeitet wurde oder in Station 1 war und schlecht bearbeitet wurde. Es beginnt also mit Station 1. In Station 2 dürfen alle Teile bearbeitet werden, die zuvor in Station 1 waren und dort gut bearbeitet wurden. Waren die Teile in Station 2 gut, dürfen sie in Station 3 bearbeitet weerden. Es kann mehrere Start-Stationen geben und mehrere Zielstationen. Ein Teil dürfte auch z.B. wie folgt durchlaufen:
Code:
Das Teil darf also von Station 2 in Station 3 oder in Station 7 kommen.
1 -> 2 -> 3 -> 4 -> 5 -> 6
| | |-> 7 ----------| Von 3 darf es nur in 4 und dann in 5 und dann in 6. Geht das Teil von 2 nach 7, darf es von 7 nur in 6 weiterbearbeitet werden. Es kann auch Fälle geben, in denen ein Teil, das in 6 schlecht wurde, wieder zurück nach 2 muss o.ä. Es gibt also beliebige Verzweigungen und Zusammenführungen. Anhand der obigen Definitionsliste (List<...>), in der die Einträge beliebig angeordnet sind, möchte ich nun alle möglichen Wege eines Teils bekommen. Entweder mit einem Baum oder irgendwie anders. So, dass ich das auch visualisieren könnte. Wie kann ich das denn machen? Eine Start-Station ist für mich eine, in der die Quell-Station = -1 ist. D.h. damit muss ich vermutlich irgendwie beginnen (wie gesagt, es kann auch mehrere Start-Stationen geben). Ich dachte evtl. an eine Struktur in der Art, aber vielleicht geht es auch schöner:
Code:
Evtl. mit Rekursion beginnend bei den Start-Staionen (Abbruchbedingungen sind: Rücksprung zu einer vorigen Station bzw. End-Station erreicht).
class EinzelneStation
{ int AktuelleStation; // "Knoten" mit der Station, in der sich das Teil geared befindet List<EinzelneStation> NaechsteStationen; // Liste von "Knoten", zu denen das aktuelle Teil als nächstes darf List<int> RuecksprungStation; // im Falle, dass das Teil wieder zurück an vorige Stationen darf, steht hier die Nr., damit es keine "Endlosschleife" gibt int BedingungFuerBearbeitungsfreigabe; } List<EinzelStation> AlleMoeglichenWege Ergebnis soll (wie auch immer) etwas in der Art sein, das mir alle möglichen Wege aufzeigt:
Code:
Konntet ihr's halbwegs nachvollziehen? :stupid:
1 (Rücksprung: 1, Bedingung: Wenn Schlechtteil in 1)
2 (Bedingung: nur Gutteil) 3 (Bedingung: nur Gutteil) ODER 1 (Rücksprung: 1, Bedingung: Wenn Schlechtteil in 1) 2 (Bedingung: nur Gutteil) 4 (Bedingung: nur Schlechtteil) ODER ... Ich möchte aus der Fahrplandefinition ermitteln, welche möglichen Wege ein Teil nehmen kann (mit den entsprechenden Bedingungen). Grüße Matze |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Ob man das mit einer gewöhnlichen Baumstruktur (TTreeView) überhaupt darstellen kann? Sieht eher nach
![]() |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Zitat:
Im Prinzip ist dein Plan ein nicht deterministischer Zustandsautomat, wobei das Tupel (Quell-Station, Teil-Art) der Zustand ist. Die Fahrplan-Einträge fügen dann eine (Gutteil/Schlechtteil) oder zwei Transitionen (alle Teile) hinzu. Dieser Automat erkennt dann alle möglichen Wege für ein Teil. |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Danke für die Antworten.
Zitat:
Zitat:
Hättest du mir dafür ein konkretes Programmierbeispiel für meinen Anwendungsfall? @Perlsau: Ich brauche keinen TreeView dafür. Ich möchte eine Struktur haben, mit der ich das z.B. als Text o.ä. ausgeben kann. Jupp, so eine Art Ablaufplan wäre das, rein grafisch betrachtet. Mir geht's jedoch erstmal darum, dass ich in der Software die möglichen Wege kenne ohne das zu Visualisieren. |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Da hat Perlsau glaub ich Recht.
Du hast ja schon einen Baum gezeichnet, der keiner ist. Wozu dient das? Optische "Validierung" der Pläne? Es gibt eine dll, graphwiz oder so, die ist glaub ich frei verfügbar und kann sowas wahrscheinlich malen. Ich hab die mal vor langer Zeit ausprobiert. Bin mir nicht sicher, aber die verarbeitet auch unterschiedliche Eingabeformate. |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Stopp!
Mir geht's NICHT um die Visualisierung. Vielleicht habe ich mich falsch ausgedrückt. Ich möchte das nur in einer internen Struktur haben, die ich ausgeben KÖNNTE, aber mir geht's hauptsächlich darum, dass die Software intern "weiß", welche möglichen Wege es gibt ohne Visualisierung. |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Liste der Anhänge anzeigen (Anzahl: 1)
Wenn du die Kreise bloß erkennen willst, dann hast du es einfacher. Eine Breiten- oder Tiefensuche sollte ausreichen.
Breitensuche: Du hast eine Menge von (unfertigen) Pfaden. In jedem Schritt erstellst du eine neue Menge, die alle Pfade enthält, die durch Herabhängen einer gültigen Folge-Station entstehen. Wenn du Kreise feststellst (den bisherigen Pfad durchgehen) oder ein Pfad das Ziel erreicht, wird er ausgegeben. Tiefensuche: Hänge an einen Pfad solange gültigen Folge-Station an, bis er entweder eine Zielstation erreicht oder eine schon besuchte Station erreicht. Dann gibst du den Pfad aus, gehst zurück zur letzten Entscheidung und probierst die nächste andere Abzweigung aus. Das ist erstmal so aus dem Handgelenk, da kann man sicher noch was optimieren :) Beachte, das du auch ohne Kreise exponentiell viele Pfade (in Anzahl der Stationen) bekommen kannst: Anhang 41294 |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Um einen gerichteten Graphen darzustellen, gibt es derlei viele Möglichkeiten. Ich favorisiere zwei:
Adjacent Matrix: Eine AdjacentMatrix A einer Knotenmenge definiert die Pfade zwischen zwei Knoten. Bei N Knoten im Graph sind i und j zwei Knoten im Graphen. Dann bezeichnet A[i,j] einen Übergang i-> genau dann, wenn A[i,j] <> e ist. (e ist bei Dir z.B. -1) A[i,j] = 0 bedeutet, das alle Teile von i->j laufen können, =1 bedeutet, nur Gutteile usw. Daneben benötigst Du noch eine Liste der Startpunkte und eine Liste der Endpunkte. Obwohl: Benötigen wirst Du sie nicht, denn es gilt: Ein Startknoten ist ein Knoten, der von keinem Knoten der Nachbar ist. Ein Endknoten ist ein Knoten, der keine Nachbarn hat. Wenn Du sehr viele Knoten hast, wird die Matrix riesig, ist aber kaum gefüllt. Dann kann man das Speicherkonzept der sparse matrix verwenden. Neighbors: Das ist eine Struktur, ähnlich deiner.
Code:
Wie man die Pfade bestimmt? Dazu hat BUG schon die Stichpunkte genannt. Hier mal C# (oder so ähnlich)
enum PathType
{ All = 0, Good = 2, Bad = 3 } interface IPath { PathType PathType{get;} INode Destination{get;} } interface INode { int ID{get;} IEnumerable<IPath> Neighbors {get;} }
Code:
Dahingetippt, ohne Editor oder Compiler.
void FindAllPaths()
{ foreach (var pathType pathType in typeof(PathType).GetValues()) { foreach (var node in StartNodes) { Visit (pathType, new List<INode>(), node) } } } void Visit (PathType pathType, List<INode> path, node) { if (visited[node]) return; visited[node] = true; path.Add(node); var matchingNeighbors = node.Neighbors.where (n=>n.PathType == pathType); if (!matchingNeighbors.Any()) { OutputPath(path); } else { foreach (var singleStep in matchingNeighbors) { Visit(pathType, path, singleStep.Destination) } } path.Remove(node); visited[node] = false; } Die Idee ist das Markieren des besuchten Knotens ('Hier war ich schon') damit werden zirkuläre Pfade vermieden. |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Ich würde hier zunächst einen kompletten Graphen aufbauen. Knotenklasse etwa so
Code:
Davon dann zunächst alle benötigten Instanzen erstellen, und von Hand den Graphen zusammenfriemeln. (Anders wird's ja nicht gehen.)
public Station
{ List<Station> NextStationsForGoodPart; List<Station> NextStationsForBadParts; String StationName; } Dann alle Start-Stations in eine "List<Station> ValidEntryPoints" (Deine Quellstation -1 quasi, für den Fall dass es da mehrere gibt mal als Liste). Jetzt kannst du beginnend mit den Stationen in dieser Liste anfangen den Graphen für alle möglichen Wege zu traversieren. Während du das tust, führst du für jeden neu begonnenen Vorgang ab einem Entry-Point eine weitere "List<Station> VisitedStations" mit, und prüfst vor jeder Verzweigung ob der nächste Knoten in dieser Liste steht. Wenn ja, dann Rückverweis an den Stationsnamen, sonst nächste Station anspringen und die aktuelle in VisitedStations merken. Beim Traversieren musst du dann natürlich beide Wege (good und bad) ablaufen und entsprechend in der Ausgabe vermerken zu welchem Zweig der Schritt gehörte. Ganz naiv gedacht das ganze, ich hoffe das klappt :) |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Zitat:
Was willst du durch die Darstellung dem Nutzer denn erleichtern? Welche Fehlerquellen sollen z.B. aufgedeckt werden? Davon würde ich dann abhängig machen, wie die Darstellung aussehen soll. Und davon ist wiederum abhängig, welche interne Darstellungsform am besten geeignet ist. Wie bereits gesagt wurde, gibt es exponenziell viele Pfade, mit Kreisen sogar unendlich viele. Da bringt es wohl wenig, einfach alle theoretisch möglichen Pfade bruteforce-mäßig auszugeben. :glaskugel: Die Glaskugel sagt, dass eine ![]() |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Letztendlich ist halt wirklich die Frage, was du damit machen willst.
Wenn die Anzahl der Stationen klein ist oder die Eigenschaften der Verknüpfung günstig, dann macht es vielleicht wirklich Sinn, alle Pfade auszugeben. Bei mehr als ein paar dutzend Pfaden würde ich das aber bezweifeln. Du könntest anstelle einzelnen Pfade auch einen Prefixbaum ausgeben, das würde die Sache dann deutlich übersichtlicher machen, in extremen Fällen würde es nicht helfen. Es folgt: Werbung für theoretischere Informatik in der Industrie :wink: Wenn du ein schönen Model suchst, um Abläufe mit komplexe Abhängigkeiten zu untersuchen, sind vielleicht Petri-Netze was für dich. Je nach Ziel könntest du dich mit temporaler Logik auseinandersetzen, was Fragen erlaubt, die wie folgt aussehen: Kann es ein Werkstück geben, das Station 1 erreicht, nachdem es Station 2 in schlechter Qualität verlassen hat. Bei kleineren Problem könnte man auch mit naiv implementierte Model-Checkern Spaß haben; für größere Probleme schadet etwas Rechenpower und eine clevere Implementierung nicht. |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Die Hinweise auf den Zustandsautomaten waren ja schon ein Volltreffer.
Schau Dir mal an, wie die Windows Workflow Foundation das abbildet. Die können die Wege ja auch alle durchvalidieren und auch in einem Workflow-Designer darstellen. WF ist leider nicht Teil der .NET Foundation und damit (noch?) nicht Open Source, aber mit dotPeek kann man da dennoch ziemlich gut reingucken ;-) |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Zitat:
Eine Liste von Start und Zielstationen, damit kann man sehr einfach feststellen, wo es von einem gegebenen Standpunkt hin gehen kann. Ein Weg dagegen dürfte erstmal sehr uninteressant sein, da es einer Software selbst egal ist, wie der Weg sein könnte (erst Recht unter dynamischen Bedingungen) Wenn es nicht um Visualisierung geht und auch nicht um Validierung: (mögliche) Wege werden doch erst spannend, wenn es um Optimierungen geht, Umwege, Teilebestandsprüfung, Vorbestellung usw. |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
Kann es sein, dass es hier einen logischen Fehler gibt?
Code:
class FahrplanEintrag
{ int QuellStation; // -1 = Keine Vorgeschichte, d.h. ZielStation = Start-Station int ZielStation; int Bedingung; } List<FahrplanEintrag> Fahrplan = new List<FahrplanEintrag>() { new FahrplanEintrag() // Station 1 ??? { QuellStation = -1, ZielStation = 1, // schon ein Ring !!! Bedingung = 0, // alle Teile }, new FahrplanEintrag() // Station 2 ??? { QuellStation = 1, ZielStation = 2, // wieder auf sich selber !!! Bedingung = 1, // nur Gutteile }, new FahrplanEintrag() // Station 3 ??? { QuellStation = 1, ZielStation = 1, Bedingung = 2, // nur Schlechtteile (erneute Bearbeitung in Station 1 zulässig) }, new FahrplanEintrag() // Station 4 ??? { QuellStation = 2, ZielStation = 3, Bedingung = 1, // nur Gutteile }, // ... } |
AW: Baumstruktur aus Daten erzeugen: Eine Herausforderung! ;-)
@SirRufo: Die Reihenfolge der Liste ist willkürlich.
Ich denke, ich bin auf dem richtigen Weg. Das hier liefert mir schon recht gute Ergebnisse:
Code:
Grüße und nochmals vielen Dank für die zahlreichen Antworten!
private void GetWorkflowPath(GlobalTypesDatabase.WorkflowTreeNode node, List<int> UsedStations)
{ UsedStations.Add(node.CurrentStation); foreach (var defSingleWf in _dbData.DefWorkflow) { if (defSingleWf.StationLogicalSrc == node.CurrentStation) { bool isJumpBack = UsedStations.IndexOf(defSingleWf.StationLogicalDest) != -1; GlobalTypesDatabase.WorkflowTreeNode newNode = new GlobalTypesDatabase.WorkflowTreeNode(); newNode.CurrentStation = defSingleWf.StationLogicalDest; if (isJumpBack) { node.JumpBackToStation.Add(defSingleWf.StationLogicalDest); } else { node.TargetStations.Add(newNode); GetWorkflowPath(newNode, UsedStations); } } } } Matze |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:30 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz