2

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).



mkpisk
  • 152
  • 1
  • 9
  • I am not sure you need `setof/3` for this. – TA_intern Oct 09 '20 at 07:24
  • You also need to provide enough useful data: bord/2, encompasses/3, geo_sea/3. – TA_intern Oct 09 '20 at 07:52
  • encompasses/3 and geo_sea/3 are facts for all the countries. examples for both of the predicate I posted above. encompasses/3 have information if a country belongs to specific continent and what percentage (3rd argument). In the example above, austria is part of europe and it is 100% within europe. – mkpisk Oct 09 '20 at 07:56
  • ```borders_sym(X,Y,L) :- borders(X,Y,L);borders(Y,X,L). bord(Country,L) :- borders_sym(_,C,L), Country = C. ``` – mkpisk Oct 09 '20 at 07:56
  • similar to encompasses and geo_space, borders predicate is also fact. – mkpisk Oct 09 '20 at 07:57
  • % borders(X,Y,L), country X borders country Y, the border is L kilometers – mkpisk Oct 09 '20 at 07:57
  • If you provide an example with enough data it is easy to write and test a query. – TA_intern Oct 09 '20 at 09:00
  • % 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). – mkpisk Oct 09 '20 at 09:07
  • ```% encompasses(C,R,Fr), country C is encompassed by region R to fraction Fr (percent) 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). ``` – mkpisk Oct 09 '20 at 09:08
  • Edit your question so that it can be copy-pasted from there at once. – TA_intern Oct 09 '20 at 09:08
  • ```% 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.'). ``` – mkpisk Oct 09 '20 at 09:09
  • Make sure you also have the special cases covered in your data; for example, a country in more than one continent. – TA_intern Oct 09 '20 at 09:09
  • Comments are not for code dumps.... use the question maybe. – TA_intern Oct 09 '20 at 09:10
  • @TA_intern sure noted – mkpisk Oct 09 '20 at 09:12
  • the predicate bord/2 that you use in circumference/2 is not defined anywhere. – TA_intern Oct 09 '20 at 09:15
  • I have updated everything – mkpisk Oct 09 '20 at 09:41

1 Answers1

0

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.
TA_intern
  • 2,222
  • 4
  • 12
  • I am not getting the same results as what you got. Countries, Country, Length, X and Y are warned as singleton variables. got an error arguments are not sufficiently instantiated. – mkpisk Oct 09 '20 at 10:04
  • @mkpisk yes, I have a couple of naming errors in the code. Can you find them? – TA_intern Oct 09 '20 at 11:07
  • yes. thank you it works. I had to do few modifications. I replaced X and Y with Length and Country, I added geo_sea predicate and after that it works perfectly. – mkpisk Oct 09 '20 at 12:10