it-swarm.com.de

Zyklen in der Stammbaum-Software

Ich bin der Entwickler einer Stammbaum-Software (geschrieben in C++ und Qt). Ich hatte keine Probleme, bis einer meiner Kunden mir einen Fehlerbericht schickte. Das Problem ist, dass der Kunde zwei Kinder mit seiner eigenen Tochter hat und daher meine Software aufgrund von Fehlern nicht verwenden kann.

Diese Fehler sind das Ergebnis meiner verschiedenen Behauptungen und Invarianten über die Verarbeitung des Familiengraphen (nach dem Durchlaufen eines Zyklus gibt das Programm beispielsweise an, dass X nicht gleichzeitig Vater und Großvater von Y sein kann).

Wie kann ich diese Fehler beheben, ohne alle Datenbehauptungen zu entfernen?

1594
Partick Höse

Es scheint, dass Sie (und/oder Ihr Unternehmen) ein grundlegendes Missverständnis darüber haben, was ein Stammbaum sein soll.

Lassen Sie mich klarstellen, ich arbeite auch für ein Unternehmen, das (als eines seiner Produkte) einen Stammbaum im Portfolio hat, und wir haben mit ähnlichen Problemen zu kämpfen.

Das Problem in unserem Fall und ich nehme auch an, dass es sich um das GEDCOM -Format handelt, bei dem die Meinung über das, was eine Familie sein sollte, äußerst groß ist. Dieses Format enthält jedoch einige schwerwiegende Missverständnisse darüber, wie ein Stammbaum wirklich aussieht.

GEDCOM hat viele Probleme, wie zum Beispiel Unvereinbarkeit mit gleichgeschlechtlichen Beziehungen, Inzest usw. Was im wirklichen Leben häufiger vorkommt, als Sie sich vorstellen (vor allem, wenn Sie in die Zeit zwischen 1700 und 1800 zurückgehen).

Wir haben unseren Stammbaum nach dem Vorbild der realen Welt erstellt: Ereignisse (z. B. Geburten, Hochzeiten, Verlobungen, Gewerkschaften, Todesfälle, Adoptionen usw.). Wir schränken diese nicht ein, außer für logisch Unmögliche (zum Beispiel kann man nicht der eigene Vater sein, Beziehungen brauchen zwei Individuen, etc ...)

Das Fehlen von Validierungen gibt uns eine "realere Welt", einfachere und flexiblere Lösung.

In diesem speziellen Fall würde ich vorschlagen, die Behauptungen zu entfernen, da sie nicht allgemein gültig sind.

Für die Anzeige von Problemen (die auftreten werden) würde ich vorschlagen, den gleichen Knoten so oft wie nötig zu zeichnen und auf die Duplizierung hinzuweisen, indem alle Kopien beim Auswählen einer davon beleuchtet werden.

727
Bert Goethals

Entspanne deine Behauptungen.

Nicht durch Änderung der Regeln, die für 99,9% Ihrer Kunden sehr hilfreich sein können, wenn sie Fehler bei der Eingabe ihrer Daten bemerken.

Ändern Sie ihn stattdessen von einem Fehler "Beziehung kann nicht hinzugefügt werden" in eine Warnung mit "Trotzdem hinzufügen".

564
Ben Voigt

Hier ist das Problem mit Stammbäumen: Sie sind keine Bäume. Sie sind gerichtete azyklische Graphen oder DAGs. Wenn ich die Prinzipien der Biologie der menschlichen Fortpflanzung richtig verstehe, wird es keine Zyklen geben.

Soweit ich weiß, akzeptieren sogar die Christen Ehen (und damit Kinder) zwischen Cousins ​​und Cousinen, was den Stammbaum in eine Familien-DAG verwandelt.

Die Moral der Geschichte lautet: Wählen Sie die richtigen Datenstrukturen.

224
exDM69

Ich vermute, dass Sie einen Wert haben, der eine Person eindeutig identifiziert, auf die Sie Ihre Schecks stützen können.

Dies ist eine schwierige Frage. Angenommen, Sie möchten die Struktur als Baum beibehalten, dann schlage ich Folgendes vor:

Angenommen, A hat Kinder mit seiner eigenen Tochter.

A fügt sich dem Programm als A und als B hinzu. Nennen wir es einmal in der Rolle des Vaters Freund.

Fügen Sie eine is_same_for_out() -Funktion hinzu, die dem ausgabegenerierenden Teil Ihres Programms mitteilt, dass alle Links, die intern zu B gehen, bei der Präsentation von Daten zu A werden sollen.

Dies bedeutet zusätzlichen Arbeitsaufwand für den Benutzer, aber die Implementierung und Wartung der IT-Lösung ist wahrscheinlich relativ einfach.

Darauf aufbauend könnten Sie an der Codesynchronisierung von A und B arbeiten, um Inkonsistenzen zu vermeiden.

Diese Lösung ist sicherlich nicht perfekt, aber ein erster Ansatz.

115
Eduard Thamm

Sie sollten sich darauf konzentrieren , was für Ihre Software wirklich von Wert ist . Lohnt sich die Zeit, die aufgewendet wird, um es für EINEN Verbraucher zum Laufen zu bringen, für die Lizenz? Wahrscheinlich nicht.

Ich rate Ihnen, sich bei diesem Kunden zu entschuldigen, ihm mitzuteilen, dass seine Situation für Ihre Software nicht in Frage kommt, und ihm eine Rückerstattung zu erteilen.

84
christopheml

Du hättest die Atreides -Familie gründen sollen (entweder modern, Dune oder uralt, Ödipus Rex ) als Testfall. Sie finden keine Fehler, wenn Sie bereinigte Daten als Testfall verwenden.

79
user779752

Dies ist einer der Gründe, warum Sprachen wie "Go" keine Behauptungen haben. Sie werden verwendet, um Fälle zu bearbeiten, an die Sie wahrscheinlich nicht allzu oft gedacht haben. Sie sollten nur das Unmögliche behaupten, nicht einfach das Unwahrscheinliche. Letzteres zu tun gibt den Behauptungen einen schlechten Ruf. Gehen Sie jedes Mal, wenn Sie assert( eingeben, zehn Minuten weg und denken Sie wirklich darüber nach.

In Ihrem besonders beunruhigenden Fall ist es sowohl denkbar als auch entsetzlich, dass eine solche Behauptung unter seltenen, aber möglichen Umständen falsch wäre. Behandeln Sie es daher in Ihrer App, wenn Sie nur sagen: "Diese Software wurde nicht für das von Ihnen vorgestellte Szenario entwickelt.".

Zu behaupten, dein Ur-Ur-Ur-Großvater sei dein Vater als unmöglich, ist eine vernünftige Sache.

Wenn ich für eine Testfirma gearbeitet hätte, die beauftragt wurde, Ihre Software zu testen, hätte ich dieses Szenario natürlich vorgestellt. Warum? Jeder jugendliche, aber intelligente "Benutzer" wird genau dasselbe tun und sich über den daraus resultierenden "Fehlerbericht" freuen.

59
Tim Post

Ich hasse es, eine derart vermasselte Situation zu kommentieren, aber der einfachste Weg, nicht alle Ihre Invarianten neu auszulösen, besteht darin, einen Phantomscheitelpunkt in Ihrem Diagramm zu erstellen, der als Proxy für den inzestuösen Vater fungiert.

41
Sean

Also habe ich ein bisschen an Family Tree Software gearbeitet. Ich denke, das Problem, das Sie zu lösen versuchen, ist, dass Sie in der Lage sein müssen, über den Baum zu laufen, ohne in Endlosschleifen zu geraten - mit anderen Worten, der Baum muss azyklisch sein.

Es sieht jedoch so aus, als ob Sie behaupten, dass es nur einen Weg zwischen einer Person und einem ihrer Vorfahren gibt. Das garantiert, dass es keine Zyklen gibt, ist aber zu streng. Aus biologischer Sicht ist Nachkommenschaft ein gerichteter azyklischer Graph (DAG). Der Fall, den Sie haben, ist sicherlich ein entarteter Fall, aber so etwas passiert die ganze Zeit auf größeren Bäumen.

Wenn Sie zum Beispiel die 2 ^ n Vorfahren betrachten, die Sie in Generation n haben, und wenn es keine Überlappung gab, dann hätten Sie 1000 n. Chr. Mehr Vorfahren, als Menschen am Leben waren. Es muss also eine Überlappung geben.

Es besteht jedoch auch die Tendenz, dass ungültige Zyklen auftreten, nur fehlerhafte Daten. Wenn Sie den Baum überqueren, müssen Zyklen behandelt werden. Sie können dies in jedem einzelnen Algorithmus oder unter Last tun. Ich habe es unter Last gemacht.

Es gibt verschiedene Möglichkeiten, echte Zyklen in einem Baum zu finden. Der falsche Weg ist, jeden Vorfahren einer bestimmten Person zu markieren. Wenn beim Überqueren die Person, zu der Sie als Nächstes wechseln möchten, bereits markiert ist, trennen Sie die Verknüpfung. Dadurch werden potenziell genaue Beziehungen getrennt. Der richtige Weg, dies zu tun, besteht darin, bei jedem Individuum zu beginnen und jeden Vorfahren mit dem Pfad zu diesem Individuum zu markieren. Wenn der neue Pfad den aktuellen Pfad als Unterpfad enthält, ist dies ein Zyklus und sollte unterbrochen werden. Sie können Pfade als Vektor <bool> (MFMF, MFFFMF usw.) speichern, was den Vergleich und die Speicherung sehr schnell macht.

Es gibt ein paar andere Möglichkeiten, um Zyklen zu erkennen, z. B. zwei Iteratoren zu senden und zu prüfen, ob sie jemals mit dem Teilmengen-Test kollidieren. Am Ende habe ich jedoch die lokale Speichermethode verwendet.

Beachten Sie auch, dass Sie den Link nicht wirklich trennen müssen. Sie können ihn einfach von einem normalen Link in einen "schwachen" Link ändern, dem einige Ihrer Algorithmen nicht folgen. Sie sollten auch vorsichtig sein, wenn Sie den Link auswählen, der als schwach markiert werden soll. Manchmal können Sie anhand der Geburtsdaten herausfinden, wo der Zyklus unterbrochen werden soll, aber oft können Sie nichts herausfinden, weil so viele Daten fehlen.

37
tfinniga

Eine andere falsche Antwort auf eine dumme Frage:

Die eigentliche Antwort lautet: Verwenden Sie eine geeignete Datenstruktur. Die menschliche Genealogie kann nicht vollständig mit einem reinen Baum ohne Zyklen ausgedrückt werden. Sie sollten eine Art Diagramm verwenden. Sprechen Sie auch mit einem Anthropologen, bevor Sie fortfahren, da es viele andere Stellen gibt, an denen ähnliche Fehler beim Versuch gemacht werden könnten, die Genealogie zu modellieren, selbst im einfachsten Fall einer "westlichen patriarchalischen monogamen Ehe".

Auch wenn wir die hier diskutierten lokalen Tabubeziehungen ignorieren möchten, gibt es viele völlig legale und völlig unerwartete Möglichkeiten, Zyklen in einen Stammbaum einzuführen.

Zum Beispiel: http://en.wikipedia.org/wiki/Cousin_marriage

Grundsätzlich ist die Cousinehe nicht nur weit verbreitet und zu erwarten, sondern auch der Grund, warum Menschen von Tausenden kleiner Familiengruppen auf eine Weltbevölkerung von 6 Milliarden angewachsen sind. Es kann nicht anders funktionieren.

Es gibt wirklich sehr wenige Universalien, wenn es um Genealogie, Familie und Abstammung geht. Fast jede strenge Annahme über Normen, die besagen, wer eine Tante sein kann oder wer wen heiraten kann oder wie Kinder zum Zweck der Vererbung legitimiert sind, kann durch eine Ausnahme irgendwo auf der Welt oder in der Geschichte gestört werden.

36
clvrmnky

Abgesehen von den potenziellen rechtlichen Auswirkungen scheint es sicherlich erforderlich zu sein, einen 'Knoten' in einem Stammbaum als Vorgängerperson zu behandeln, anstatt davon auszugehen, dass der Knoten die einzige Person sein kann.

Bitten Sie den Baumknoten, eine Person sowie die Nachfolger einzuschließen. Anschließend können Sie einen weiteren Knoten im Baum haben, der dieselbe Person mit verschiedenen Nachfolgern enthält.

20
Will A

Einige Antworten haben Möglichkeiten aufgezeigt, die Behauptungen/Invarianten beizubehalten, aber dies scheint ein Missbrauch von Behauptungen/Invarianten zu sein. Behauptungen sollen sicherstellen, dass etwas, das wahr sein sollte, wahr ist, und Invarianten sollen sicherstellen, dass sich etwas, das sich nicht ändern sollte, nicht ändert.

Was Sie hier behaupten, ist, dass es keine inzestuösen Beziehungen gibt. Es ist klar, dass sie do existieren, sodass Ihre Behauptung ungültig ist. Sie können diese Behauptung umgehen, aber der eigentliche Fehler liegt in der Behauptung selbst. Die Behauptung sollte entfernt werden.

13
kerkeslager

Ihr Stammbaum sollte gerichtete Beziehungen verwenden. Auf diese Weise haben Sie keinen Zyklus.

8

Genealogische Daten sind zyklisch und passen nicht in ein azyklisches Diagramm. Wenn Sie also Aussagen gegen Zyklen haben, sollten Sie diese entfernen.

Die Möglichkeit, dies in einer Ansicht zu handhaben, ohne eine benutzerdefinierte Ansicht zu erstellen, besteht darin, das zyklische übergeordnete Element als übergeordnetes Element "ghost" zu behandeln. Mit anderen Worten, wenn eine Person für dieselbe Person sowohl Vater als auch Großvater ist, wird der Großvaterknoten normal angezeigt, aber der Vaterknoten wird als "Geister" -Knoten mit einer einfachen Bezeichnung wie "Großvater sehen" gerendert. ) und zeigt auf den Großvater.

Um Berechnungen durchführen zu können, müssen Sie möglicherweise Ihre Logik für die Behandlung von zyklischen Diagrammen verbessern, damit ein Knoten bei einem Zyklus nicht mehrmals besucht wird.

5
Tyler Durden

Behauptungen überleben die Realität nicht

Normalerweise überleben Behauptungen den Kontakt mit realen Daten nicht. Es ist ein Teil des Prozesses der Softwareentwicklung, zu entscheiden, mit welchen Daten Sie sich befassen möchten und welche außerhalb des Bereichs liegen.

Zyklische Familiendiagramme

In Bezug auf "Stammbäume" (in Wirklichkeit sind es ausgewachsene Graphen, einschließlich Zyklen) gibt es eine nette Anekdote:

Ich habe eine Witwe geheiratet, die eine erwachsene Tochter hatte. Mein Vater, der uns oft besuchte, verliebte sich in meine Stieftochter und heiratete sie. Infolgedessen wurde mein Vater mein Sohn und meine Tochter meine Mutter. Einige Zeit später gab ich meiner Frau einen Sohn, der der Bruder meines Vaters war, und meinen Onkel. Die Frau meines Vaters (die auch meine Tochter und meine Mutter ist) hat einen Sohn bekommen. Als Ergebnis bekam ich einen Bruder und einen Enkel in derselben Person. Meine Frau ist jetzt meine Großmutter, weil sie die Mutter meiner Mutter ist. Ich bin also der Ehemann meiner Frau und gleichzeitig der Stiefenkel meiner Frau. Mit anderen Worten, ich bin mein eigener Opa.

Noch seltsamer wird es, wenn man Leihmutterschaft oder "verschwommene Vaterschaft" berücksichtigt.

Wie gehe ich damit um?

Definieren Sie Zyklen als außerhalb des Bereichs

Sie können entscheiden, dass Ihre Software solche seltenen Fälle nicht behandeln soll. In diesem Fall sollte der Benutzer ein anderes Produkt verwenden. Dies macht die Behandlung der häufigeren Fälle wesentlich robuster, da Sie mehr Aussagen und ein einfacheres Datenmodell beibehalten können.

Fügen Sie in diesem Fall Ihrer Software einige gute Import- und Exportfunktionen hinzu, damit der Benutzer bei Bedarf problemlos auf ein anderes Produkt migrieren kann.

Manuelle Beziehungen zulassen

Sie können dem Benutzer erlauben, manuelle Beziehungen hinzuzufügen. Diese Beziehungen sind keine "Bürger erster Klasse", d. H. Die Software nimmt sie als solche an, überprüft sie nicht und verarbeitet sie nicht im Hauptdatenmodell.

Der Benutzer kann dann seltene Fälle von Hand behandeln. Ihr Datenmodell bleibt weiterhin recht einfach und Ihre Aussagen werden überleben.

Seien Sie vorsichtig mit manuellen Beziehungen. Es besteht die Versuchung, sie vollständig konfigurierbar zu machen und somit ein vollständig konfigurierbares Datenmodell zu erstellen. Dies wird nicht funktionieren: Ihre Software wird nicht skaliert, Sie werden seltsame Fehler bekommen und schließlich wird die Benutzeroberfläche unbrauchbar. Dieses Anti-Pattern heißt "soft coding" , und "The daily WTF" steckt voller Beispiele dafür.

Machen Sie Ihr Datenmodell flexibler, überspringen Sie Behauptungen und testen Sie Invarianten

Der letzte Ausweg wäre, Ihr Datenmodell flexibler zu gestalten. Sie müssten fast alle Behauptungen überspringen und Ihr Datenmodell auf einem vollständigen Diagramm aufbauen. Wie das obige Beispiel zeigt, ist es leicht möglich, Ihr eigener Großvater zu sein, so dass Sie sogar Fahrräder haben können.

In diesem Fall sollten Sie Ihre Software ausgiebig testen. Sie mussten fast alle Behauptungen überspringen, sodass eine gute Chance für zusätzliche Fehler besteht.

Verwenden Sie einen Testdatengenerator, um ungewöhnliche Testfälle zu überprüfen. Es gibt Quick-Check-Bibliotheken für Haskell , Erlang oder C . Für Java/Scala gibt es ScalaCheck und Nyaya . Eine Testidee wäre, eine zufällige Population zu simulieren, sie zufällig kreuzen zu lassen und dann das Ergebnis von Ihrer Software zu importieren und dann zu exportieren. Die Erwartung wäre, dass alle Verbindungen im Ausgang auch im Eingang sind und umgekehrt.

Ein Fall, in dem eine Eigenschaft gleich bleibt, wird als Invariante bezeichnet. In diesem Fall ist die Invariante die Menge der "romantischen Beziehungen" zwischen den Individuen in der simulierten Bevölkerung. Versuche so viele Invarianten wie möglich zu finden und teste sie mit zufällig generierten Daten. Invarianten können funktionell sein, z.

  • ein Onkel bleibt ein Onkel, auch wenn Sie mehr "romantische Beziehungen" hinzufügen
  • jedes Kind hat einen Elternteil
  • eine Bevölkerung mit zwei Generationen hat mindestens einen Großelternteil

Oder sie können technisch sein:

  • Ihre Software stürzt bei einer Grafik mit bis zu 10 Milliarden Mitgliedern nicht ab (unabhängig von der Anzahl der Verbindungen).
  • Ihre Software skaliert mit O(number-of-nodes) und O (Anzahl der Kanten ^ 2)
  • Ihre Software kann jedes Familiendiagramm mit bis zu 10 Milliarden Mitgliedern speichern und neu laden

Wenn Sie die simulierten Tests ausführen, werden Sie viele seltsame Eckfälle finden. Ihre Behebung wird viel Zeit in Anspruch nehmen. Außerdem werden Sie viele Optimierungen verlieren, Ihre Software wird viel langsamer ausgeführt. Sie müssen sich entscheiden, ob es sich lohnt und ob dies im Umfang Ihrer Software liegt.

4

Das Wichtigste ist, avoid creating a problem zu verwenden. Ich bin daher der Meinung, dass Sie verwenden Sie eine direkte Beziehung verwenden sollten, um einen Zyklus zu vermeiden.

Wie @ markmywords sagte, # include "fritzl.h".

Schließlich muss ich recheck your data structure sagen. Möglicherweise läuft dort etwas schief (möglicherweise löst eine bidirektionale verknüpfte Liste Ihr Problem).

4
Nasser Hadjloo

Anstatt alle Behauptungen zu entfernen, sollten Sie immer noch prüfen, ob es sich bei einer Person um einen eigenen Elternteil oder um eine andere unmögliche Situation handelt, und einen Fehler melden. Möglicherweise wird eine Warnung ausgegeben, wenn dies unwahrscheinlich ist, sodass der Benutzer weiterhin häufig auftretende Eingabefehler erkennen kann. Diese Warnung wird jedoch ausgeführt, wenn alles korrekt ist.

Ich würde die Daten in einem Vektor mit einer permanenten Ganzzahl für jede Person speichern und die Eltern und Kinder in Personenobjekten speichern, wobei das int der Index des Vektors ist. Dies würde zwischen den Generationen ziemlich schnell gehen (aber langsam für Dinge wie Namenssuche). Die Objekte wären in der Reihenfolge, in der sie erstellt wurden.

3
ctype.h