Ciclos en el software de árbol genealógico


Soy el desarrollador de algún software de árbol genealógico (escrito en C++ y Qt). No tuve problemas hasta que uno de mis clientes me envió un informe de error. El problema es que el cliente tiene dos hijos con su propia hija, y, como resultado, no puede usar mi software debido a errores.

Esos errores son el resultado de mis varias aserciones e invariantes sobre el gráfico de la familia que se está procesando (por ejemplo, después de caminar un ciclo, el programa afirma que X no puede ser padre y abuelo de Y).

¿Cómo puedo resolver esos errores sin eliminar todas las aserciones de datos?

Author: Nathaniel Ford, 2011-05-28

18 answers

Parece que usted (y/o su empresa) tiene un malentendido fundamental de lo que se supone que es un árbol genealógico.

Permítanme aclarar, también trabajo para una empresa que tiene (como uno de sus productos) un árbol genealógico en su cartera, y hemos estado luchando con problemas similares.

El problema, en nuestro caso, y supongo que el tuyo también, viene del formato GEDCOM que es extremadamente obstinado sobre lo que una familia debe ser. Sin embargo, este formato contiene algunos conceptos erróneos severos sobre cómo se ve realmente un árbol genealógico.

GEDCOM tiene muchos problemas, tales como incompatibilidad con relaciones del mismo sexo, incesto, etc... Que en la vida real sucede más a menudo de lo que te imaginas (especialmente cuando retrocedes en el tiempo a la 1700-1800).

Hemos modelado nuestro árbol genealógico a lo que sucede en el mundo real: Eventos (por ejemplo, nacimientos, bodas, compromisos, uniones, muertes, adopciones, etc.). No ponemos ninguna restricción a estos, a excepción de lógicamente imposibles (por ejemplo, uno no puede ser el propio padre, las relaciones necesitan dos individuos, etc.)...)

La falta de validaciones nos da una solución más "real", más simple y más flexible.

En cuanto a este caso específico, sugeriría eliminar las afirmaciones, ya que no se sostienen universalmente.

Para mostrar los problemas (que surgirán) sugeriría dibujar el mismo nodo tantas veces como sea necesario, insinuando la duplicación iluminando todas las copias en seleccionar uno de ellos.

 727
Author: Bert Goethals,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-06 14:47:55

Relaja tus afirmaciones.

No cambiando las reglas, que en su mayoría son muy útiles para el 99.9% de sus clientes para detectar errores al ingresar sus datos.

En su lugar, cámbielo de un error "no se puede agregar relación" a una advertencia con un "agregar de todos modos".

 564
Author: Ben Voigt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-28 19:20:12

Aquí está el problema con los árboles genealógicos: no son árboles. Se dirigen gráficos acíclicos o DAGs. Si entiendo correctamente los principios de la biología de la reproducción humana, no habrá ciclos.

Hasta donde yo sé, incluso los cristianos aceptan matrimonios (y por lo tanto hijos) entre primos, lo que convertirá el árbol genealógico en una familia DAG.

La moraleja de la historia es: elegir las estructuras de datos correctas.

 224
Author: exDM69,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-01 14:07:29

Supongo que tienes algún valor que identifica de manera única a una persona en la que puedes basar tus cheques.

Esto es complicado. Suponiendo que desea mantener la estructura en un árbol, sugiero esto:

Asume esto: A tiene hijos con su propia hija.

A se añade al programa como A y como B. Una vez en el papel de padre, llamémoslo novio.

Agregue una función is_same_for_out() que le dice a la parte generadora de salida de su programa que todos los enlaces ir a B internamente debe ir a A en la presentación de datos.

Esto hará un trabajo extra para el usuario, pero supongo que sería relativamente fácil de implementar y mantener.

A partir de eso, podría trabajar en la sincronización de código A y B para evitar inconsistencias.

Esta solución seguramente no es perfecta, pero es un primer enfoque.

 115
Author: Eduard Thamm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-27 19:48:55

Usted debe centrarse en lo que realmente hace valor para su software. ¿El tiempo dedicado a hacer que funcione para un consumidor vale el precio de la licencia ? Probablemente no.

Le aconsejo que se disculpe con este cliente, le diga que su situación está fuera del alcance de su software y le emita un reembolso.

 84
Author: christopheml,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-01 09:55:02

Deberías haber creado la familia Atreides (ya sea moderna, Duna, o antiguo, Edipo Rex) como un caso de prueba. Usted no encuentra errores mediante el uso de datos desinfectados como un caso de prueba.

 79
Author: user779752,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-27 19:58:09

Esta es una de las razones por las que lenguajes como "Go" no tienen aserciones. Se utilizan para manejar casos en los que probablemente no pensaste, con demasiada frecuencia. Solo debes afirmar lo imposible, no simplemente lo improbable. Hacer esto último es lo que le da a las afirmaciones una mala reputación. Cada vez que escribas assert(, aléjate durante diez minutos y realmente piénsalo.

En su caso particularmente inquietante, es tanto concebible como espantoso que tal afirmación sería falso bajo circunstancias raras pero posibles. Por lo tanto, manejarlo en su aplicación, aunque solo sea para decir "Este software no fue diseñado para manejar el escenario que presentó".

Afirmar que tu tatara, tatara, tatara abuelo siendo tu padre como imposible es una cosa razonable de hacer.

Si yo estuviera trabajando para una empresa de pruebas que fue contratado para probar su software, por supuesto que habría presentado ese escenario. ¿Por qué? Cada joven pero inteligente 'usuario' va a hacer exactamente lo mismo y disfrutar en el resultado 'informe de error'.

 59
Author: Tim Post,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-02 07:47:37

Odio comentar sobre una situación tan jodida, pero la forma más fácil de no volver a ajustar todos sus invariantes es crear un vértice fantasma en su gráfico que actúa como un proxy de vuelta al padre incestuoso.

 41
Author: Sean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-28 18:55:14

Así que, he hecho algo de trabajo en el software de árbol genealógico. Creo que el problema que estás tratando de resolver es que tienes que ser capaz de caminar por el árbol sin entrar en bucles infinitos - en otras palabras, el árbol tiene que ser acíclico.

Sin embargo, parece que estás afirmando que solo hay un camino entre una persona y uno de sus antepasados. Eso garantizará que no hay ciclos, pero es demasiado estricto. Biológicamente hablando, la descendencia es un grafo acíclico dirigido (DAG). El caso que tienes es ciertamente un caso degenerado, pero ese tipo de cosas sucede todo el tiempo en árboles más grandes.

Por ejemplo, si nos fijamos en los 2^n antepasados que tienen en la generación n, si no hubiera superposición, entonces usted tendría más antepasados en 1000 DC que había personas vivas. Por lo tanto, tiene que haber superposición.

Sin embargo, también tiende a obtener ciclos que no son válidos, solo datos incorrectos. Si estás atravesando el árbol, entonces los ciclos deben ser tratados. Usted puede hacer esto en cada uno algoritmo individual, o en carga. Lo hice en carga.

Encontrar ciclos verdaderos en un árbol se puede hacer de varias maneras. La forma incorrecta es marcar cada ancestro de un individuo dado, y al atravesar, si la persona a la que vas a pasar ya está marcada, entonces corta el enlace. Esto romperá relaciones potencialmente precisas. La manera correcta de hacerlo es comenzar desde cada individuo, y marcar a cada ancestro con el camino hacia ese individuo. Si la nueva ruta contiene la ruta actual como un subpath, entonces es un ciclo, y debe ser roto. Puede almacenar rutas como vector (MFMF, MFFFMF, etc.) lo que hace que la comparación y el almacenamiento muy rápido.

Hay algunas otras formas de detectar ciclos, como enviar dos iteradores y ver si alguna vez chocan con la prueba de subconjunto, pero terminé usando el método de almacenamiento local.

También tenga en cuenta que no necesita cortar realmente el enlace, solo puede cambiarlo de un enlace normal a un enlace' débil', que no es seguido de algunos de sus algoritmos. También querrá tener cuidado al elegir qué enlace marcar como débil; a veces puede averiguar dónde se debe romper el ciclo mirando la información de la fecha de nacimiento, pero a menudo no puede averiguar nada porque faltan muchos datos.

 37
Author: tfinniga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-26 12:59:03

Otra respuesta seria para una pregunta tonta:

La verdadera respuesta es utilizar una estructura de datos apropiada. La genealogía humana no puede expresarse completamente usando un árbol puro sin ciclos. Deberías usar algún tipo de gráfico. También, hablar con un antropólogo antes de ir más lejos con esto, porque hay un montón de otros lugares errores similares se podrían hacer tratando de modelar la genealogía, incluso en el caso más simple de "matrimonio monógamo patriarcal occidental."

Incluso si como se discute aquí, hay muchas formas perfectamente legales y completamente inesperadas de introducir ciclos en un árbol genealógico.

Por ejemplo: http://en.wikipedia.org/wiki/Cousin_marriage

Básicamente, el matrimonio de primos no solo es común y esperado, es la razón por la que los humanos han pasado de miles de pequeños grupos familiares a una población mundial de 6 mil millones. No puede funcionar de otra manera.

Realmente Hay muy pocos universales cuando se trata de genealogía, familia y linaje. Casi cualquier suposición estricta sobre las normas que sugieren quién puede ser una tía, o quién puede casarse con quién, o cómo los niños son legitimados con el propósito de la herencia, puede ser molesto por alguna excepción en algún lugar del mundo o la historia.

 36
Author: clvrmnky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-01 14:12:54

Posibles implicaciones legales aparte, ciertamente parece que necesita tratar a un 'nodo' en un árbol genealógico como una persona predecesora en lugar de asumir que el nodo puede ser la única persona.

Haga que el nodo del árbol incluya a una persona así como a los sucesores, y luego puede tener otro nodo más abajo del árbol que incluya a la misma persona con diferentes sucesores.

 20
Author: Will A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-28 18:56:43

Algunas respuestas han mostrado formas de mantener las aserciones/invariantes, pero esto parece un mal uso de las aserciones/invariantes. Las aserciones son para asegurarse de que algo que debería ser cierto es cierto, y los invariantes son para asegurarse de que algo que no debería cambiar no cambie.

Lo que estás afirmando aquí es que las relaciones incestuosas no existen. Claramente ellosexisten , por lo que su afirmación es inválida. Puede trabajar alrededor de esta afirmación, pero el error real está en la afirmación sí mismo. La afirmación debe ser eliminada.

 13
Author: kerkeslager,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-01 19:55:59

Su árbol genealógico debe usar relaciones dirigidas. De esta manera no tendrás un ciclo.

 8
Author: Patrick Cornelissen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-27 19:52:44

Los datos genealógicos son cíclicos y no encajan en un gráfico acíclico, por lo que si tiene aserciones contra ciclos debe eliminarlas.

La forma de manejar esto en una vista sin crear una vista personalizada es tratar al padre cíclico como un padre "fantasma". En otras palabras, cuando una persona es tanto un padre como un abuelo de la misma persona, entonces el nodo abuelo se muestra normalmente, pero el nodo padre se representa como un nodo "fantasma"que tiene una etiqueta simple como ("ver abuelo") y señala al abuelo.

Para hacer cálculos es posible que necesite mejorar su lógica para manejar gráficos cíclicos de modo que un nodo no se visite más de una vez si hay un ciclo.

 5
Author: Tyler Durden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-12 19:08:20

Lo más importante es avoid creating a problem, así que creo que deberías usar una relación directa para evitar tener un ciclo.

Como dijo @markmywords, #incluye "fritzl.h".

Finalmente tengo que decir recheck your data structure. Tal vez algo va mal allí (tal vez una lista enlazada bidireccional resuelve su problema).

 4
Author: Nasser Hadjloo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-25 10:26:21

Las afirmaciones no sobreviven a la realidad

Por lo general, las afirmaciones no sobreviven al contacto con datos del mundo real. Es parte del proceso de ingeniería de software decidir, con qué datos desea tratar y cuáles están fuera de alcance.

Gráficos de familias cíclicas

Con respecto a los "árboles" familiares (de hecho son gráficos completos, incluidos los ciclos), hay una anécdota agradable:

Me casé con una viuda que tenía una hija adulta. Mi padre, que nos visitaba a menudo, se enamoró con mi hijastra y me casé con ella. Como resultado, mi padre se convirtió en mi hijo, y mi hija se convirtió en mi madre. Algún tiempo después, le di a mi esposa un hijo, que era el hermano de mi padre, y mi tío. La esposa de mi padre (que también es mi hija y mi madre) tuvo un hijo. Como resultado, tengo un hermano y un nieto en la misma persona. Mi esposa es ahora mi abuela, porque es la madre de mi madre. Así que soy el esposo de mi esposa, y al mismo tiempo el hijastro de mi esposa. En otras palabras, Soy mi propio abuelo.

Las cosas se vuelven aún más extrañas, cuando se tienen en cuenta los sustitutos o "paternidad difusa".

Cómo lidiar con eso

Definir ciclos como fuera de alcance

Usted podría decidir que su software no debe tratar con casos tan raros. Si tal caso ocurre, el usuario debe utilizar un producto diferente. Esto hace que lidiar con los casos más comunes sea mucho más robusto, ya que puede mantener más aserciones y datos más simples modelo.

En este caso, agregue algunas buenas funciones de importación y exportación a su software, para que el usuario pueda migrar fácilmente a un producto diferente cuando sea necesario.

Permitir relaciones manuales

Puede permitir que el usuario agregue relaciones manuales. Estas relaciones no son "ciudadanos de primera clase", es decir, el software las toma tal cual, no las comprueba y no las maneja en el modelo de datos principal.

El usuario puede manejar casos raros a mano. Su modelo de datos todavía manténgase bastante simple y sus afirmaciones sobrevivirán.

Tenga cuidado con las relaciones manuales. Existe la tentación de hacerlos completamente configurables y, por lo tanto, crear un modelo de datos totalmente configurable. Esto no funcionará: Su software no escalará, obtendrá errores extraños y finalmente la interfaz de usuario se volverá inutilizable. Este anti-patrón se llama "soft coding", y "The daily WTF" está lleno de ejemplos para eso.

Haga su modelo de datos más flexible, saltar aserciones, invariantes de prueba

El último recurso sería hacer que su modelo de datos sea más flexible. Tendría que omitir casi todas las aserciones y basar su modelo de datos en un gráfico completo. Como muestra el ejemplo anterior, es fácilmente posible ser tu propio abuelo, por lo que incluso puedes tener ciclos.

En este caso, debe probar ampliamente su software. Tuvo que omitir casi todas las afirmaciones, por lo que hay una buena probabilidad de errores adicionales.

Utilice un dato de prueba generador para comprobar casos de prueba inusuales. Hay bibliotecas de comprobación rápida para Haskell, Erlang o C. Para Java / Scala hay ScalaCheck y Nyaya. Una idea de prueba sería simular una población aleatoria, dejar que se entrecruzara al azar, luego dejar que su software primero importe y luego exporte el resultado. La expectativa sería, que todas las conexiones en la salida son también en la entrada y vice verso.

Un caso, donde una propiedad permanece lo mismo se llama invariante. En este caso, el invariante es el conjunto de "relaciones románticas" entre los individuos en la población simulada. Trate de encontrar la mayor cantidad posible de invariantes y pruébelos con datos generados aleatoriamente. Los invariantes pueden ser funcionales, por ejemplo:

  • un tío sigue siendo un tío, incluso cuando añades más "relaciones románticas"{[58]]}
  • cada niño tiene un padre
  • una población con dos generaciones tiene al menos un abuelo{[58]]}

O ellos puede ser técnico:

  • Su software no se bloqueará en un gráfico de hasta 10 mil millones de miembros (no importa cuántas interconexiones)
  • Su software escala con O(número de nodos) y O (número de aristas^2)
  • Su software puede guardar y volver a cargar cada gráfico de la familia hasta 10 mil millones de miembros

Al ejecutar las pruebas simuladas, encontrará muchos casos de esquina extraños. Arreglarlos llevará mucho tiempo. También perderá una gran cantidad de optimizaciones, su el software se ejecutará mucho más lento. Usted tiene que decidir, si vale la pena y si esto está en el alcance de su software.

 4
Author: stefan.schwetschke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-26 14:48:45

En lugar de eliminar todas las aserciones, aún debe verificar cosas como que una persona sea su propio padre u otras situaciones imposibles y presentar un error. Tal vez emitir una advertencia si es poco probable que el usuario todavía puede detectar errores de entrada comunes, pero funcionará si todo es correcto.

Almacenaría los datos en un vector con un entero permanente para cada persona y almacenaría los padres y los hijos en objetos personales donde dicho int es el índice del vector. Este sería bastante rápido ir entre generaciones (pero lento para cosas como las búsquedas de nombres). Los objetos estarían en orden de cuando fueron creados.

 3
Author: ctype.h,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-02 10:19:49

Duplicar el padre (o utilizar enlace simbólico/referencia).

Por ejemplo, si está utilizando una base de datos jerárquica:

$ #each person node has two nodes representing its parents.
$ mkdir Family
$ mkdir Family/Son
$ mkdir Family/Son/Daughter
$ mkdir Family/Son/Father
$ mkdir Family/Son/Daughter/Father
$ ln -s Family/Son/Daughter/Father Family/Son/Father
$ mkdir Family/Son/Daughter/Wife
$ tree Family
Family
└── Son
    ├── Daughter
    │   ├── Father
    │   └── Wife
    └── Father -> Family/Son/Daughter/Father

4 directories, 1 file
 -3
Author: numeric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-13 04:39:52