我是一名家谱软件的开发人员(使用C++和Qt编写)。我之前没有遇到问题,直到有一位客户给我发送了一个错误报告。问题在于该客户有两个孩子都与自己的女儿生过孩子,导致我的软件出现错误而无法使用。
这些错误是因为我在处理家庭图表时使用了各种断言和不变量(例如,在遍历循环后,程序会声明X不能同时是Y的父亲和祖父)。
我如何解决这些错误而不必删除所有数据断言?
我是一名家谱软件的开发人员(使用C++和Qt编写)。我之前没有遇到问题,直到有一位客户给我发送了一个错误报告。问题在于该客户有两个孩子都与自己的女儿生过孩子,导致我的软件出现错误而无法使用。
这些错误是因为我在处理家庭图表时使用了各种断言和不变量(例如,在遍历循环后,程序会声明X不能同时是Y的父亲和祖父)。
我如何解决这些错误而不必删除所有数据断言?
看起来您(或您所在的公司)对家谱的理解存在根本性误解。
让我澄清一下,我也在一家公司工作,该公司的产品之一就是家谱,我们一直在努力解决类似的问题。
这个问题,在我们的情况下,我认为在您的情况下也是如此,源于GEDCOM格式,这个格式非常关注一个家庭应该是什么样子。然而,这个格式包含了一些关于一个家谱真正应该长什么样的严重误解。
GEDCOM存在很多问题,例如与同性关系、乱伦等不兼容……这在现实生活中比您想象的要更加普遍(尤其是回到18世纪和19世纪时期)。
我们将家谱建模成符合现实世界的形式:事件(例如出生、婚礼、订婚、结合、死亡、领养等等)。我们对这些事件没有任何限制,除了逻辑不可能的限制(例如一个人不能是自己的父母,关系需要两个人等等)。
缺乏验证使我们拥有了一个更“真实世界”的、更简单和更灵活的解决方案。
至于这个具体案例,我建议删除这些断言,因为它们并不普遍适用。
对于(即将出现的)显示问题,我建议根据需要重复绘制同一节点,并通过在选择其中一个节点时点亮所有副本来暗示重复。
放宽你的断言。
不是通过改变规则,这些规则对于99.9%的客户在捕捉输入数据错误方面非常有用。
相反,将其从一个错误“无法添加关系”更改为带有“仍要添加”的警告。
家谱的问题在于:它们不是树。它们是有向无环图,或者称为 DAG。如果我正确理解了人类繁殖生物学的原理,就不会出现循环。
据我所知,即使基督教徒也接受表兄妹之间的婚姻(和后代),这将使家族谱变成一个家族 DAG。
寓意是:选择合适的数据结构。
我猜您有一些唯一识别人物的价值信息可以作为验证依据。
这是一个棘手的问题。假设您想保持树形结构,我建议如下:
假设这样: A
和他自己的女儿生了孩子。
A
以 A
和 B
的身份添加到程序中。在父亲的角色中,我们称之为男朋友。
添加一个 is_same_for_out()
函数,告诉您的程序输出生成部分,所有指向内部的链接从 B
应该改为在数据呈现时指向 A
。
这会给用户带来额外的工作量,但我认为实现和维护都相对容易。
在此基础上,您可以通过编写代码同步更新 A
和 B
来避免不一致性。
这个解决方案肯定不完美,但是这是初步的尝试。
你应该关注于真正为你的软件创造价值的事情。把时间花在让它适用于一个客户身上是否值得支付许可证费?很可能不是。
我建议你向这个客户道歉,告诉他他的情况超出了你的软件范围,并给他退款。
assert(
时,离开十分钟并且认真考虑一下。我很讨厌评论这样一个混乱的情况,但是不改变所有不变量的最简单方法是在您的图表中创建一个幽灵顶点,作为一个代理人回到乱伦父亲。
所以,我已经对家谱软件进行了一些工作。我认为你试图解决的问题是需要能够在不进入无限循环的情况下遍历树-换句话说,树必须是非循环的。
然而,看起来你断言一个人和他们的祖先之间只有一条路径。这将确保没有循环,但过于严格。从生物学角度来看,后代是一个有向无环图(DAG)。你所拥有的情况肯定是退化的情况,但这种情况在更大的树上经常发生。
例如,如果你看一下第n代中有2^n个祖先,如果没有重叠,那么在公元1000年,你会拥有比当时还活着的人更多的祖先。因此,必须有重叠。
然而,你也会得到无效的循环,只是坏数据。如果你正在遍历树,则必须处理循环。你可以在每个单独的算法中或在加载时执行此操作。我是在加载时完成的。
在树中查找真正的循环可以用几种方法来完成。错误的方法是标记给定个体的每个祖先,并且在遍历时,如果您要跳转到的人已经被标记,则切断链接。这将切断潜在准确的关系。正确的方法是从每个个体开始,并使用到该个体的路径标记每个祖先。如果新路径包含当前路径作为子路径,则它是一个循环,并应该被打破。您可以将路径存储为vector<bool> (MFMF、MFFFMF等),这使得比较和存储非常快速。对于一个愚蠢的问题,另一个嘲讽性的模拟回答:
真正的答案是使用适当的数据结构。人类的家谱不能完全用没有循环的纯树来表达。你应该使用某种图形。此外,在继续处理这个问题之前,与人类学家交谈,因为在试图建立家谱模型时,即使在“西方父权制一夫一妻制”的最简单情况下,也有很多类似错误的地方。
即使我们想忽略本地禁忌关系(如本文所述),也有很多完全合法且完全意想不到的方法可以将循环引入家谱中。
例如:http://en.wikipedia.org/wiki/Cousin_marriage
基本上,堂兄婚姻不仅普遍而且被期望,这是人类从成千上万的小家庭群体走向全球60亿人口的原因。它不能以其他方式工作。
当涉及到家谱、家庭和血统时,真正的普遍规律非常少。几乎任何关于规范的严格假设,比如谁可以成为姑妈,或者谁可以嫁给谁,或者孩子如何被合法化以便继承,都可能被世界上某个地方或历史上的某个例外所推翻。