Search code examples
prologpredicate

Predicate with longest land border using mondial - prolog


I am trying to write a predicate with longest land border using some help from Prolog, finding largest value from a setOf list. The issue I am facing here is the generated output is not what I am expected.

The current output from my code generated descending order by 'circumference' of all the countries and continents. But I need only one entry (with highest circumference) from each continent and secondly countries that are located in more than one continent can not be included in the output.

my code:

lb_country(Continent, Country):-
    setof(L-R-C, X^Y^Z^( encompasses(C, R, X),
                         \+ geo_sea(Y, C, Z),
                         circumference(L, C) ), Cs),
    reverse(Cs, HighToLowAreas),
    member(_-Continent-Country, HighToLowAreas).

Included predicate circumference is defined as


borders_sym(X,Y,L) :- borders(X,Y,L);borders(Y,X,L). 
bord(Country,L) :-     borders_sym(_,C,L),     Country = C.

circumference(C, Country) :-
    setof(P, bord(Country,P), List),sum_list(List,C).

example of encompasses and geo_sea

% encompasses(C,R,Fr), country C is encompassed by region R to fraction Fr (percent)
encompasses(austria,'Europe',100).
encompasses(austria,'Europe',100).
encompasses(afghanistan,'Asia',100).
encompasses(antigua_and_barbuda,'America',100).
encompasses(albania,'Europe',100).
encompasses(american_samoa,'Australia/Oceania',100).
encompasses(andorra,'Europe',100).
encompasses(angola,'Africa',100).
encompasses(armenia,'Asia',100).
encompasses(aruba,'America',100).
encompasses(australia,'Australia/Oceania',100).
encompasses(anguilla,'America',100).
encompasses(azerbaijan,'Asia',100).
encompasses(bangladesh,'Asia',100).
encompasses(barbados,'America',100).
encompasses(benin,'Africa',100).
encompasses(bermuda,'America',100).
encompasses(belgium,'Europe',100).
encompasses(burkina_faso,'Africa',100).
encompasses(pitcairn_islands,'Australia/Oceania',100).
encompasses(pakistan,'Asia',100).
encompasses(poland,'Europe',100).
encompasses(papua_new_guinea,'Australia/Oceania',100).
encompasses(puerto_rico,'America',100).
encompasses(paraguay,'America',100).
encompasses(qatar,'Asia',100).
encompasses(argentina,'America',100).
encompasses(russia,'Asia',75).
encompasses(botswana,'Africa',100).
encompasses(central_african_republic,'Africa',100).
encompasses(taiwan,'Asia',100).
encompasses(congo,'Africa',100).
encompasses(chile,'America',100).
encompasses(reunion,'Australia/Oceania',100).
encompasses(russia,'Europe',25).



% geo_sea(N,C,P), the sea N is in country C in province P
geo_sea('Andaman Sea',india,'Andaman and Nicobar Is.').
% geo_sea(N,C,P), the sea N is in country C in province P
geo_sea('Andaman Sea',india,'Andaman and Nicobar Is.').
geo_sea('Andaman Sea',myanmar,'Ayeyarwady').
geo_sea('Andaman Sea',myanmar,'Bago').
geo_sea('Andaman Sea',myanmar,'Mon').
geo_sea('Andaman Sea',myanmar,'Yangon').
geo_sea('Andaman Sea',indonesia,'Aceh').
geo_sea('Andaman Sea',thailand,'Thailand').
geo_sea('Arabian Sea',india,'Goa').
geo_sea('Arabian Sea',india,'Gujarat').
geo_sea('Arabian Sea',india,'Karnataka').
geo_sea('Arabian Sea',india,'Kerala').
geo_sea('Arabian Sea',india,'Lakshadweep Is.').
geo_sea('Arabian Sea',india,'Maharashtra').
geo_sea('Arabian Sea',oman,'Oman').
geo_sea('Arabian Sea',pakistan,'Balochistan').
geo_sea('Arabian Sea',pakistan,'Sindh').
geo_sea('Arctic Ocean',canada,'Northwest Territories').

borders predicate

% borders(X,Y,L), country X borders country Y, the border is L kilometers
borders(austria,switzerland,164).
borders(austria,czech_republic,362).
borders(austria,germany,784).
borders(afghanistan,china,76).
borders(afghanistan,iran,936).
borders(afghanistan,pakistan,2430).
borders(afghanistan,tajikistan,1206).
borders(afghanistan,turkmenistan,744).
borders(afghanistan,uzbekistan,137).
borders(austria,liechtenstein,37).
borders(austria,hungary,366).
borders(austria,italy,430).
borders(albania,greece,282).
borders(albania,kosovo,112).
borders(albania,macedonia,151).
borders(albania,montenegro,172).
borders(andorra,spain,65).
borders(andorra,france,60).
borders(angola,namibia,1376).




Solution

  • For circumference/2, you can write:

    circumference(Country, C) :-
        findall(Km, ( border(Country, _, Km) ; border(_, Country, Km) ), Kms),
        sum_list(Kms, C).
    

    The table encompasses/3 has the full list of countries? Then, you could define "country entirely on one continent" as: encompasses(Country, _, 100)?

    To group by continents, and only list contries entirely on the continent, you can do:

    ?- bagof(Country, encompasses(Country, Continent, 100), Countries).
    Continent = 'Africa',
    Countries = [angola, benin, burkina_faso] ;
    Continent = 'America',
    Countries = [antigua_and_barbuda, aruba, anguilla, barbados, bermuda] ;
    Continent = 'Asia',
    Countries = [afghanistan, armenia, azerbaijan, bangladesh] ;
    Continent = 'Australia/Oceania',
    Countries = [american_samoa, australia] ;
    Continent = 'Europe',
    Countries = [austria, albania, andorra, belgium].
    

    You can now do as in your question: add the circumference, order by it, reverse, take the first element:

    longest_border(Continent, Country, Length) :-
        bagof(N-C,
              (   encompasses(C, Continent, 100),
                  circumference(C, N)
              ),
              Cs),
        keysort(Countries, S),
        reverse(S, [X-Y|_]).
    

    But you have a lot of data missing. I get:

    ?- longest_border(Continent, Country, Length).
    Continent = 'Africa',
    Country = angola,
    Length = 1376 ;
    Continent = 'America',
    Country = bermuda,
    Length = 0 ;
    Continent = 'Asia',
    Country = afghanistan,
    Length = 5529 ;
    Continent = 'Australia/Oceania',
    Country = australia,
    Length = 0 ;
    Continent = 'Europe',
    Country = austria,
    Length = 2143.