web-dev-qa-db-ja.com

家系図ソフトウェアのサイクル

私はいくつかの家系図ソフトウェア(C++およびQtで書かれています)の開発者です。私の顧客の一人が私にバグ報告を送ってくれるまで私は何の問題もありませんでした。問題は、顧客に2人の子供が自分の娘と一緒にいて、その結果、エラーのために彼が私のソフトウェアを使用できないことです。

これらのエラーは、処理されている家族グラフに関する私のさまざまな主張と不変性の結果です(たとえば、サイクルを歩いた後、プログラムはXがYの父親と祖父の両方になることはできないと述べています)。

すべてのデータアサーションを削除せずにこれらのエラーを解決する方法を教えてください。

1594
Partick Höse

あなた(および/またはあなたの会社)は、家系図がどうあるべきかについて基本的な誤解をしているようです。

明確にしておきますが、私は(その製品の1つとして)ポートフォリオに家系図を持っている会社のために働いています、そして私たちは同様の問題に苦しんでいます。

私たちの場合の問題は、私の場合もそうですが、私の場合もそうですが、 _ gedcom _ 形式から来ています。しかし、この形式には、家系図が実際にどのように見えるのかについての重大な誤解が含まれています。

GEDCOMには、同性関係との相性の悪さ、近親相姦など、さまざまな問題があります。

私たちは、家系図を現実の世界で起こることにモデル化しました:出来事(例えば、誕生、結婚式、婚約、労働組合、死、養子縁組など)。論理的に不可能なものを除いて、私たちはこれらにいかなる制限も加えません(例えば、人は自分自身の親になることはできません、関係は2人の個人を必要とする、など)。

検証がないことで、より「現実的な」、よりシンプルで柔軟なソリューションが得られます。

この特定のケースに関しては、私たちは普遍的に成り立つものではないので、アサーションを削除することをお勧めします。

問題を表示するには(発生することになります)、必要に応じて同じノードを何度も描き、そのうちの1つを選択してすべてのコピーを点灯させることで、重複を暗示します。

727
Bert Goethals

あなたの主張を緩めなさい。

ルールの変更によるものではありません。これは、99.9%の顧客にとって、データ入力時の間違いを捉えるのに非常に役立つ可能性が高いです。

代わりに、エラーを「関係を追加できません」から「とにかく追加」の警告に変更します。

564
Ben Voigt

これが家系図の問題です。それらは木ではありません。それらは有向非巡回グラフまたはDAGです。私が人間の生殖の生物学の原理を正しく理解しているならば、どんなサイクルもありません。

私の知る限りでは、クリスチャンでさえも、いとこの間の結婚(そしてそれゆえに子供)を受け入れ、それは家系図を家族DAGに変えるでしょう。

ストーリーのモラルは、正しいデータ構造を選択することです。

224
exDM69

私はあなたがあなたがあなたの小切手の基礎となることができる人をユニークに識別するある価値を持っていると思います。

これはトリッキーなものです。あなたが構造を木に保ちたいと仮定すると、私はこれを提案する:

Aは自分の娘と子供がいます。

Aは、自分自身をAおよびBとしてプログラムに追加します。父の役になったら、それを彼氏と呼びましょう。

is_same_for_out()関数を追加して、プログラムの出力生成部分に、内部的にBに向かうリンクはすべてデータの表示時にAに向かうように指示します。

これはユーザーにとって余分な作業になりますが、ITの導入と保守は比較的簡単に行えると思います。

それを基にして、矛盾を避けるためにABを同期させるコードを作成することができます。

この解決策は確かに完璧ではありませんが、最初のアプローチです。

115
Eduard Thamm

あなたは に焦点を当てるべきです - 本当にあなたのソフトウェアに価値をもたらすもの 。 1人の消費者のために機能させるのに費やす時間は、ライセンスの価格に見合う価値がありますか?そうではないでしょう。

私はあなたにこの顧客に謝罪して、彼の状況があなたのソフトウェアの範囲外であることを彼に話して、そして彼に払い戻しを出すことを彼に言うことを勧めます。

84
christopheml

テストケースとして、 Atreides ファミリー(現代、 Dune 、または古代、 Oedipus Rex のいずれか)を設定しておく必要があります。テストケースとしてサニタイズされたデータを使用してもバグは見つかりません。

79
user779752

これが、 "Go"のような言語にアサーションがない理由の1つです。それらは、あなたがおそらく考えていなかったケースを処理するために使われています。 あなたはただ不可能ということではなく、不可能だけを主張すべきです 。後者をすることは主張に悪い評判を与えるものです。 assert(とタイプするたびに、10分歩き、 本当に と考えてください。

あなたの特に憂慮すべき事件では、そのような主張がまれではあるが可能性のある状況の下では偽物になるだろうということは想像もできないし、恐ろしいことでもあります。したがって、「このソフトウェアは、あなたが提示したシナリオを処理するようには設計されていませんでした」と言うだけの場合は、アプリで処理します。

あなたの偉大な、偉大な、偉大な祖父が不可能としてあなたの父親であることを主張するのは合理的なことです。

私があなたのソフトウェアをテストするために雇われたテスト会社のために働いていたら、もちろん私はそのシナリオを提示したでしょう。どうして?すべての年少でありながら知的な「ユーザ」は、 まったく同じこと を実行しようとしており、結果として生じる 'バグレポート'を楽しんでいます。

59
Tim Post

私はそのような厄介な状況についてコメントするのは嫌いですが、あなたの不変式のすべてを再調整しないための最も簡単な方法は、近親相姦お父さんへの代用として機能するあなたのグラフに仮想頂点を作成することです。

41
Sean

それで、私は家系図ソフトウェアに関するいくつかの仕事をしました。私があなたが解決しようとしている問題は、あなたが無限のループに入らずに木を歩くことができる必要があるということです - 言い換えれば、木は非循環的である必要があります。

しかし、人とその先祖のうちの1人との間にはただ1つの道しかないと主張しているように見えます。それはサイクルがないことを保証しますが、厳しすぎます。生物学的に言えば、子孫は 有向非巡回グラフ (DAG)です。あなたが持っているケースは確かに退化したケースですが、そのようなことはいつもより大きな木で起こります。

たとえば、世代nで2 ^ nの先祖を見た場合、重複がなければ、1000年には生きている人よりも多くの先祖がいることになります。それで、重複があるべきです。

しかし、あなたはまた、無効なサイクルを取得する傾向があります。悪いデータです。あなたが木を横切っているならば、サイクルは対処されなければなりません。これは個々のアルゴリズムごとに、または負荷時に実行できます。私は負荷でそれをしました。

ツリーの中で真のサイクルを見つけることは、いくつかの方法で行うことができます。間違った方法は与えられた個人からのすべての祖先をマークすることです、そして横断するとき、あなたが次に進むことになる人がすでにマークされているならば、そしてリンクを切ってください。これは潜在的に正確な関係を切断します。それを行う正しい方法は、各個人から始めて、その個人へのパスで各祖先をマークすることです。新しいパスに現在のパスがサブパスとして含まれている場合、それはサイクルであり、壊れているはずです。パスをベクトル<ブール>(MFMF、MFFFMFなど)として格納できます。これにより、比較と格納が非常に高速になります。

2つのイテレータを送信してサブセットテストと衝突するかどうかを確認するなど、サイクルを検出する方法は他にもいくつかありますが、最終的にはローカルストレージ方式を使用しました。

また、実際にリンクを切断する必要はないことに注意してください。通常のリンクから「弱い」リンクに変更するだけで済みます。これには、一部のアルゴリズムが続くことはありません。どのリンクを弱いとマークするかを選択するときにも注意が必要です。生年月日の情報を見ればどこでサイクルが途切れているのか判断できる場合もありますが、多くのデータが欠落しているために何も見つけられないことがよくあります。

37
tfinniga

愚かな質問に対するもう一つの偽の真剣な答え:

本当の答えは、適切なデータ構造を使用することです。人間の系譜は、周期のない純粋な木を使って完全に表現することはできません。あなたはある種のグラフを使うべきです。また、これ以上先に進む前に人類学者に相談してください。他の多くの場所で同様のエラーが、「西洋家父長制の一夫一婦結婚」の最も単純な場合でもモデル化しようとする可能性があるため。

ここで説明したようにローカルでタブー関係を無視したいとしても、家系図に循環を導入するための完全に合法的で全く予想外の方法がたくさんあります。

例: http://en.wikipedia.org/wiki/Cousin_marriage

基本的に、従兄弟の結婚は一般的で予想されるだけでなく、人間が何千もの小さな家族グループから60億人の世界的な人口へと変化した理由です。他の方法では機能しません。

それが系図学、家族および系統に関しては本当に非常に少数の普遍があります。誰が叔母になれるのか、誰が誰と結婚できるのか、またはどのようにして相続のために正当化されるのかを示唆する規範についての厳密な仮定は、世界または歴史のどこかでの例外によって動揺することがあります。

36
clvrmnky

潜在的な法的な意味は別として、ノードが唯一の人であると仮定するのではなく、家系図の「ノード」を前任者として扱う必要があるようです。

ツリーノードに人とその後継者を含めるようにします。そして、同じ人と異なる後継者を含む別のノードをツリーの下の方に配置できます。

20
Will A

いくつかの回答でアサーション/不変式を保持する方法が示されていますが、これはアサーション/不変式の誤用のようです。アサーションは、本来あるべきものが正しいことを確認することであり、不変式は、変更されるべきではないものが変更されないことを確認することです。

ここで主張しているのは、近親相姦の関係は存在しないということです。明らかにそれらは do 存在するので、あなたの主張は無効です。この主張を回避することはできますが、本当のバグは主張自体にあります。アサーションは削除する必要があります。

13
kerkeslager

あなたの家系図は有向関係を使うべきです。このようにあなたはサイクルを持っていないでしょう。

8

家系図データは循環的であり、非循環グラフには収まりません。したがって、サイクルに対してアサーションがある場合は、それらを削除する必要があります。

カスタムビューを作成せずにビューでこれを処理する方法は、巡回親を「ゴースト」親として扱うことです。つまり、ある人物が同じ人物の父親でも祖父でもある場合、その祖父ノードは通常どおり表示されますが、父ノードは( "see grandfather"のような単純なラベルを持つ "ゴースト"ノードとしてレンダリングされますそして、祖父を指します。

計算を行うためには、循環グラフがある場合にノードが複数回訪問されないように、循環グラフを処理するようにロジックを改善する必要があります。

5
Tyler Durden

アサーションは現実を乗り越えない

通常、アサーションは現実世界のデータとの接触を乗り越えて生き残れません。ソフトウェアエンジニアリングのプロセスの中で、どのデータを扱いたいのか、どれが範囲外なのかを判断するのはその一部です。

巡回族グラフ

家族の「木」(実際にはそれはサイクルを含む本格的なグラフです)に関して、ニースの逸話があります:

私は成長した娘がいた未亡人と結婚しました。よく私たちを訪問した私の父は私の継女と恋に落ち、彼女と結婚しました。その結果、私の父は私の息子になり、私の娘は私の母親になりました。しばらくして、私は私の妻に私の父の兄弟である息子と私の叔父を与えました。私の父の妻(私の娘であり私の母でもあります)は息子をもうけました。その結果、私は同一人物の中に兄と孫がいました。私の妻は私の祖母です。なぜなら彼女は私の母親の母親だからです。だから私は私の妻の夫であり、同時に私の妻の継子でもあります。言い換えれば、私は私自身のおじいちゃんです。

サロゲート または "ファジィ父権"を考慮に入れると、事態はさらに奇妙になります。

それにどう対処するか

サイクルを範囲外として定義する

あなたはあなたのソフトウェアがそのようなまれなケースを扱うべきではないと決めることができます。そのような場合は、ユーザーは別の製品を使用する必要があります。これにより、より多くのアサーションとより単純なデータモデルを維持できるため、より一般的なケースへの対処がより堅牢になります。

この場合は、必要なときに簡単に別の製品に移行できるように、優れたインポートおよびエクスポート機能をソフトウェアに追加してください。

手動の関係を許可する

あなたはユーザーに手動のリレーションを追加することを許可することができます。これらの関係は「一流の市民」ではありません。すなわち、ソフトウェアはそれらを現状のままとみなし、それらをチェックせず、メインデータモデルでそれらを処理しません。

ユーザーは手でまれなケースを扱うことができます。あなたのデータモデルは依然として非常に単純なままであり、あなたの主張は生き残るでしょう。

手動の関係には注意してください。それらを完全に構成可能にし、それゆえ完全に構成可能なデータモデルを作成したいという誘惑があります。これはうまくいきません:あなたのソフトウェアは拡張されないでしょう、あなたは奇妙なバグを得るでしょうそして最終的にユーザーインターフェースは使用不可能になるでしょう。このアンチパターンは "ソフトコーディング" 、および "The daily WTF" /と呼ばれています。

データモデルをより柔軟にし、アサーションをスキップし、不変式をテストする

最後の手段は、データモデルをより柔軟にすることです。ほとんどすべてのアサーションをスキップし、データモデルを本格的なグラフに基づいて作成する必要があります。上記の例が示すように、あなた自身の祖父になることは容易に可能です、それであなたはサイクルさえ持つことができます。

この場合は、ソフトウェアを徹底的にテストする必要があります。ほとんどすべてのアサーションをスキップしなければならなかったので、追加のバグがある可能性があります。

テストデータジェネレータを使用して、異常なテストケースをチェックしてください。 HaskellErlang 、または _ c _ 用のクイックチェックライブラリがあります。 Java/Scalaの場合、 ScalaCheck および Nyaya があります。テストのアイデアの1つは、ランダムな母集団をシミュレートし、それをランダムに交配させてから、まずソフトウェアにインポートしてから結果をエクスポートさせることです。期待されることは、出力内のすべての接続は入力内にもその逆にもあるということです。

プロパティが同じままであるケースは、不変条件と呼ばれます。この場合、不変量は、模擬母集団内の個人間の「ロマンチックな関係」の集合です。できるだけ多くの不変式を見つけ、ランダムに生成されたデータでそれらをテストするようにしてください。不変式は機能的であり得る。

  • たとえあなたがもっと「ロマンチックな関係」を加えたとしても、おじはおじにとどまります
  • すべての子供は親を持っています
  • 2世代の人口に少なくとも1人の祖父母がいる

あるいは、彼らは技術的なことができます:

  • あなたのソフトウェアは、最大100億のメンバーまでグラフ上でクラッシュしません(相互接続の数に関係なく)。
  • あなたのソフトウェアはO(number-of-nodes)とO(エッジ数^ 2)でスケーリングします。
  • あなたのソフトウェアは、最大100億人のメンバーまですべての家族グラフを保存して再読み込みすることができます。

シミュレートされたテストを実行することによって、あなたはたくさんの奇妙なコーナーケースを見つけるでしょう。それらを修正することは多くの時間がかかるでしょう。また、あなたは多くの最適化を失うでしょう、あなたのソフトウェアははるかに遅くなります。それはそれが価値があるかどうか、そしてこれがあなたのソフトウェアの範囲内であるかどうか、あなたが決める必要があります。

4

最も重要なことはavoid creating a problemである、それで私はあなたがサイクルを持つことを避けるために 直接の関係 を使うべきであると信じる。

@markmywordsが言ったように、 #include "fritzl.h"。

最後にrecheck your data structureと言わなければなりません。多分何か問題があります(おそらく双方向リンクリストがあなたの問題を解決します)。

4
Nasser Hadjloo

すべてのアサーションを削除するのではなく、自分が自分の親であるなどの不可能な状況をチェックしてエラーを表示する必要があります。ユーザーが一般的な入力エラーを検出することがそれほど可能性が低いと思われる場合は、警告を発行することもありますが、すべて問題がない場合は機能します。

私は各人のための永久的な整数でベクトルでデータを格納して、言われたintがベクトルのインデックスである人のオブジェクトで親と子を格納するでしょう。これは世代間の移動がかなり速いでしょう(しかし名前検索のようなもののためには遅くなります)。オブジェクトは作成時の順になります。

3
ctype.h