Search code examples
prolog

A program that displays the number of all descendants of this person's family tree


Sample database:

descendant("son","father")
descendant("son","father")
descendant("son","father")

etc..

Sample of Tree

For "J" number of descendants = 0.
For "A" number of descendants = 8.

I made a program, but for some reason it does not count correctly, and if there are too many branches, it outputs "False".

descendant('B', 'A').
descendant('F', 'A').
descendant('D', 'B').
descendant('E', 'B').
descendant('G', 'F').
descendant('H', 'G').
descendant('I', 'G').
descendant('J', 'G').

 

num_of_descendant('G', 0).
num_of_descendant(N,Nb) :-
    descendant(P,N), 
    num_of_descendant(P,Nb1), 
    Nb is Nb1+1.

Update:

descendant('Игорь', 'Рюрик').
descendant('Ольга', 'Игорь').
descendant('Святослав Игоревич', 'Ольга').
descendant('Ярополк', 'Святослав Игоревич').
descendant('Святополк Окаянный', 'Ярополк').
descendant('Владимир Святой', 'Святослав Игоревич').
descendant('Ярослав I Мудрый', 'Владимир Святой').
descendant('Святослав', 'Ярослав I Мудрый').
descendant('Олег', 'Святослав').
descendant('Всеволод II', 'Олег').
descendant('Изяслав I', 'Ярослав I Мудрый').
descendant('Святополк', 'Изяслав I').
descendant('Всеволод I', 'Ярослав I Мудрый').
descendant('Владимир Мономах', 'Всеволод I').
descendant('Мстислав Великий', 'Владимир Мономах').
descendant('Изяслав II', 'Мстислав Великий').
descendant('Ярополк', 'Владимир Мономах').
descendant('Юрий Долгорукий', 'Владимир Мономах').
descendant('Владимир Мономах', 'Всеволод I').
descendant('Михаил I', 'Юрий Долгорукий').
descendant('Всеволод III Большое Гнездо', 'Юрий Долгорукий').
descendant('Юрий II', 'Всеволод III Большое Гнездо').
descendant('Ярослав II', 'Всеволод III Большое Гнездо').
descendant('Андрей', 'Ярослав II').
descendant('Василий', 'Андрей').
descendant('Константин', 'Василий').
descendant('Дмитрий Суздальский', 'Константин').
descendant('Василий Костромской', 'Ярослав II').
descendant('Ярослав III Тверской', 'Ярослав II').
descendant('Михаил II Святой', 'Ярослав III Тверской').
descendant('Александр II', 'Михаил II Святой').
descendant('Александр Невский', 'Ярослав II').
descendant('Андрей Городецкий', 'Александр Невский').
descendant('Дмитрий Переяславский', 'Александр Невский').
descendant('Даниил Московский', 'Александр Невский').
descendant('Юрий III Московский', 'Даниил Московский').
descendant('Иоанн I Калита', 'Даниил Московский' ).
descendant('Симеон Гордый', 'Иоанн I Калита').
descendant('Иоанн II Кроткий', 'Иоанн I Калита').
descendant('Дмитрий Донской', 'Иоанн II Kроткий').
descendant('Василий I', 'Дмитрий Донской').
descendant('Василий II Темный', 'Василий I').
descendant('Иоанн III', 'Василий II Темный').
descendant('Василий III', 'Иоанн III').
descendant('Иоанн IV', 'Василий III').
descendant('Федор', 'Иоанн IV').
descendant('Константин', 'Всеволод III Большое Гнездо').


descendant_path(Lower, Upper) :-
    descendant(Down1, Upper),
    (Down1 = Lower ; descendant_path(Lower, Down1)).

descendants_count(TopLevel, Count) :-
    aggregate_all(count, Desc, descendant_path(Desc, TopLevel), Count).

Picture of tree: Click

For "Александр Невский" number of descendents = 14,but your code return count = 7. I think your code stops on "Иоанн II Кротый" and doesn't count the rest of the descendants.


Solution

  • Using aggregate_all/4

    descendant('B', 'A').
    descendant('F', 'A').
    descendant('D', 'B').
    descendant('E', 'B').
    descendant('G', 'F').
    descendant('H', 'G').
    descendant('I', 'G').
    descendant('J', 'G').
    
    
    descendant_path(Lower, Upper) :-
        descendant(Down1, Upper),
        (Down1 = Lower ; descendant_path(Lower, Down1)).
    
    descendants_count(TopLevel, Count) :-
        aggregate_all(count, Desc, descendant_path(Desc, TopLevel), Count).
    

    Result in swi-prolog:

    ?- time(descendants_count('A', Count)).
    % 67 inferences, 0.000 CPU in 0.000 seconds (96% CPU, 627294 Lips)
    Count = 8.
    
    ?- time(descendants_count('J', Count)).
    % 27 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 358585 Lips)
    Count = 0.
    
    ?- time(descendants_count('F', Count)).
    % 47 inferences, 0.000 CPU in 0.000 seconds (95% CPU, 496110 Lips)
    Count = 4.
    

    Beware of mis-spellings and character mis-matches:

    ?- "Иоанн II Kроткий" = "Иоанн II Кроткий".
    false.
    
    ?- "K" = "К".
    false.