Zuerst hoffe ich mit diesem doch etwas überlangen Beitrag in dem viel diskutierten Thread keinen Unmut zu erregen. Falls es Michaa7 oder Huo lieber ist könnte man den Beitrag in einen neuen Thread auslagern oder komplett löschen. Ich möchte hier meine Erkenntnisse zusammenfassen. Dabei geht es nicht um die vielen Nebenkriegsschauplätze.
In diesem lang diskutierten Thread ging es um die Verträglichkeit verschiedener Pflanzen miteinander. Dabei haben die Pflanzen die Eigenschaft, dass sie mit einigen potentiellen Nachbarpflanzen gut auskommen und mit anderen überhaupt nicht. Die Frage des Autors bestand darin, ob und wie man einen Algorithmus erstellen oder nutzen könnte, aus einer Liste von Pflanzen und deren Verträglichkeit verschiedene Gruppen zusammen zu stellen, die untereinander keine Unverträglichkeiten zeigen.
Der User Huo erstellte im Laufe der Diskussionen ein Python Programm, das eine Liste von Pflanzen und eine Tabelle von Verträglichkeiten aufbereitete, mit dem Python Paket networkx verarbeitete und schliesslich eine Anzahl von Gruppen möglicher Pflanzen ohne Unverträglichkeiten ausgab.
Die Liste von Pflanzen bestand aus 11 Arten von Ananas bis Papaya. Die Verträglichkeiten wurden in zwei csv Dateien beschrieben, und zwar enemies.csv und friends.csv. In den zwei Dateien wurde die Beziehung zweier Pflanzen beschrieben. Ein Eintrag in friends.csv bedeutete, dass sich die Pflanzen gut vertragen. Entsprechend bedeutete ein Eintrag in enemies.csv, dass die zwei Pflanzen sich nicht vertragen. Jede beliebige Kombination der Pflanzen aus der Liste der 11 Arten findet sich entweder in friends.csv oder enemies.csv wieder. Damit sind die Verträglichkeiten aller Kombinationen eindeutig definiert. Das Python Programm von Huo überprüft die Dateien auf Plausibilität und bricht die Verarbeitung ab, wenn in den Dateien etwas nicht konsistent ist.
Das Programm kann nun mit einem Parameter aufgerufen werden. Dieser Parameter ist die Hauptpflanze, die per Definition in jeder Gruppe von untereinander verträglichen Pflanzen Mitglied ist. Folgerichtig ist die Untermenge der Pflanzen, die überhaupt in Frage kommen in guter Verträglichkeit mit der Hauptfrucht. So reduzierte Huo die Anzahl der möglichen Kombinationen erheblich. Im Beispiel einer Hauptfrucht Ananas bleiben von den 11 Arten nur die 6 der mit der Ananas verträglichen Pflanzen übrig. Bei der Hauptfrucht Litschi bleiben nur 3 mit der Litschi verträglichen Pflanzen übrig.
Im Programm von Huo kommt nun das Python Paket networkx ins Spiel, in dem Algorithmen basierend auf der Graphentheorie implementiert sind. Zuerst wird eine Klasse Graph erzeugt. Eingangsdaten sind im Falle der Ananas eine Liste der verträglichen Nachbarn der Ananas. Hier sind es also 6 Elemente. In dem Graphen sind alle 6 Elemente in jeder Kombination miteinander verbunden. Hier sind es 15 Kombinationen. Darunter sind nun auch Kombinationen von Pflanzen, die sich nicht vertragen. Diese werden mit networkx entfernt. Es verbleiben im Graph nur Kombinationen untereinander verträglicher Pflanzen. Diese werden mit dem Befehl find_Cliques(G) in Gruppen zusammengefasst. Das ist aber auch die am schwierigsten zu lösende Aufgabe. Im Programm von Huo werden diese Cliques formatiert ausgegeben.
Im Fall dieses einfachen Szenarios mit den logischen Beziehungen verträglich oder unverträglich kann man auch anders herum das Problem lösen. Voraussetzung ist, dass man die Operationen von Einfügen und Entfernen in beliebiger Reihenfolge durchführen kann
Ausgangspunkt ist wieder die Liste der mit der Hauptfrucht verträglichen Pflanzen. Hier dient die Ananas als Beispiel. Dazu kommt eine Tabelle der mit der Hauptfrucht verträglichen Pflanzen, die sich aber untereinander nicht vertragen.
Code: Alles auswählen
Gute Nachbarn:
Baobab, Dattel, Feige, Kiwi, Litschi, Papaya
Darunter harmonieren nicht:
['Baobab', 'Kiwi'] (1)
['Baobab', 'Papaya'] (2)
['Dattel', 'Kiwi'] (3)
['Feige', 'Kiwi'] (4)
['Feige', 'Papaya'] (5)
['Kiwi', 'Litschi'] (6)
Der Algorithmus funktioniert nun wie folgt. Initial hat man eine Gruppe mit den mit der Hauptfrucht verträglichen Pflanzen. Nun wird der erste Konflikt dadurch beseitigt, in dem man aus der initialen Gruppe zwei Gruppen macht. Beide Gruppen entstehen aus der initialen Gruppe. Nur ist in der ersten Gruppe die erste Konfliktpflanze entfernt und bei der zweiten Gruppe die zweite Konfliktpflanze. Die zwei Gruppen entstehen im Beispiel nun so.
Code: Alles auswählen
Konflikt | Ausgangsgruppe(n) | Nächste Gruppe(n) | Bemerkung
-------------|----------------------------------------------|---------------------------------------|----------------
Baobab, Kiwi | Baobab, Dattel, Feige, Kiwi, Litschi, Papaya | Dattel, Feige, Kiwi, Litschi, Papaya | Baobab entfernt
| | Baobab, Dattel, Feige, Litschi, Papaya| Kiwi entfernt
-------------|----------------------------------------------|---------------------------------------|----------------
Die Ausgangsgruppe wird nicht mehr verwendet und entfernt. Nun werden die weiteren Konflikte suksessive abgebaut, und zwar für alle neuen Gruppen. Falls in einer Ausgangsgruppe keine Unverträglichkeit für den betrachteten Konfliktfall auftritt, so wird diese Gruppe unverändert übernommen. Sind zwei Ausgangsgruppen identisch, so kann man sie zusammenfassen beziehungsweise eine der identischen Gruppen entfernen. Es geht im Beispiel nun weiter.
Code: Alles auswählen
Konflikt | Ausgangsgruppe(n) | Nächste Gruppe(n) | Bemerkung
----------------| ---------------------------------------|--------------------------------|---------------
Baobab, Papaya | Dattel, Feige, Kiwi, Litschi, Papaya | unverändert | kein Konflikt
|....................................... | .............................. | ...............
| Baobab, Dattel, Feige, Litschi, Papaya | Dattel, Feige, Litschi, Papaya | Baobab entfernt
| " " " " " | Baobab, Dattel, Feige, Litschi | Papaya entfernt
----------------| ---------------------------------------|--------------------------------|---------------
Dattel, Kiwi | Dattel, Feige, Kiwi, Litschi, Papaya | Feige, Kiwi, Litschi, Papaya | Dattel entfernt
| " " " " " | Dattel, Feige, Litschi, Papaya | Kiwi entfernt
|....................................... | .............................. | ...............
| Dattel, Feige, Litschi, Papaya | unverändert | kein Konflikt
| Baobab, Dattel, Feige, Litschi | unverändert | kein Konflikt
----------------| ---------------------------------------|--------------------------------|---------------
Feige, Kiwi | Feige, Kiwi, Litschi, Papaya | Kiwi, Litschi, Papaya | Feige entfernt
| " " " " | Feige, Litschi, Papaya | Kiwi entfernt
|....................................... | .............................. | ...............
| Dattel, Feige, Litschi, Papaya | unverändert aber doppelten | kein Konflikt
| Dattel, Feige, Litschi, Papaya | unverändert Eintrag entfernt | kein Konflikt
|....................................... | .............................. | ...............
| Baobab, Dattel, Feige, Litschi | unverändert | kein Konflikt
----------------| ---------------------------------------|--------------------------------|---------------
Feige, Papaya | Kiwi, Litschi, Papaya | unverändert | kein Konflikt
|....................................... | .............................. | ...............
| Feige, Litschi, Papaya | Litschi, Papaya | Feige entfernt
| " " " | Feige, Litschi | Papaya entfernt
|....................................... | .............................. | ...............
| Dattel, Feige, Litschi, Papaya | Dattel, Litschi, Papaya | Feige entfernt
| " " " " | Dattel, Feige, Litschi | Papaya entfernt
|....................................... | .............................. | ...............
| Baobab, Dattel, Feige, Litschi | unverändert | kein Konflikt
----------------| ---------------------------------------|--------------------------------|---------------
Kiwi, Litschi | Kiwi, Litschi, Papaya | Litschi, Papaya | Kiwi entfernt
| " " " | Kiwi, Papaya | Litschi entfernt
|....................................... | .............................. | ...............
| Litschi, Papaya | unverändert | kein Konflikt
| Feige, Litschi | unverändert | kein Konflikt
| Dattel, Litschi, Papaya | unverändert | kein Konflikt
| Dattel, Feige, Litschi | unverändert | kein Konflikt
| Baobab, Dattel, Feige, Litschi | unverändert | kein Konflikt
----------------| ---------------------------------------|--------------------------------|---------------
Nun werden die Gruppen in Cliquen zusammengefasst. Dazu werden doppelte Einträge zu einem Eintrag zusammengefasst. Das gleiche gilt auch für Gruppen, die eine Teilmenge anderer Gruppen darstellen.
Code: Alles auswählen
Nummer | Gruppe | Reduktion auf Cliquen | Bemerkung
-------|---------------------------------|-----------------------|---------
1 | Litschi, Papaya | Untergruppe von 5 | entfernt
2 | Kiwi, Papaya | |
3 | Litschi, Papaya | Untergruppe von 5 | entfernt
4 | Feige, Litschi | Untergruppe von 6 | entfernt
5 | Dattel, Litschi, Papaya | |
6 | Dattel, Feige, Litschi | Untergruppe von 7 | entfernt
7 | Baobab, Dattel, Feige, Litschi | |
Die resultierenden Cliquen sind zusammen mit der Hauptfrucht
Code: Alles auswählen
['Ananas', 'Kiwi', 'Papaya']
['Ananas', 'Dattel', 'Litschi', 'Papaya']
['Ananas', 'Baobab', 'Dattel', 'Feige', 'Litschi']
Das Ergebnis stimmt mit der Ausgabe des Programms von Huo überein. Nun habe ich selbst ein auf dem Skript von Huo basierendes Python Skript geschrieben. Das Skript von Huo habe ich nur so verändert, dass in der ersten Ausgabe eine Reihe von Minus Zeichen als Trennung ausgegeben wird. In der folgenden Zeile wird zusätzlich der Name der Hauptfrucht mit angezeigt. Mein Python Programm verwendet die selben Eingangs- und Ausgabe Funktionen wie das Skript von Huo. Damit kann man in einem kleinen Shellskript beide Programme für alle Arten aus den von Huo gelisteten Sortiment laufen lassen und die Ausgaben in Dateien umlenken. Ein Vergleich ergibt bis auf zum Teil unterschiedliche Reihenfolgen in den ermittelten Cliquen keine Unterschiede.
Ein Mathematiker könnte sehr wahrscheinlich eine Äquivalenz der zwei Methoden formal beweisen. Mein Skript muss ich noch ablegen. Der gezeigte Algorithmus sollte sich wie vom Threadstarter angeregt sogar in einer Tabellenkalkulation implementieren lassen. Vielen Dank an Michaa7 für die Anregung, an Huo für seine hervorragende Referenz Implementierung und an Heisenberg für seine Tips per PN zur uproblematischen Handhabung von Textblöcken, die in Monospace Fonts dargestellt werden sollen.
Viele Grüße,
Christoph --- das Skript lege ich noch ab.