write a predicate from other predicates by filtering based on predicate attributes with arithmetic operations

173 views Asked by At

I wanted to write a predicate from an existing predicates from mondial. The predicate i am interested in is cc(Country) says that Country is a country such that there is a city in the country where the population makes up for at least 75% of the total population in the country. there are some countries where the population is unknown and therefore the value is null.

example of given predicates:

% city(N,C,R,Pop) is a city by name N in country C in region R with
% population Pop
city('Aachen',germany,'Nordrhein Westfalen',247113).
city('Aalborg',denmark,'Nordjylland',113865).
city('Aarau',switzerland,'Aargau',null).
city('Aarhus',denmark,'Midtjylland',194345).
city('Abaetetuba',brazil,'Para',106753).
city('Abakaliki',nigeria,'Ebonyi',null).
city('Abakan',russia,'Rep. of Khakassiya',161000).
city('Abancay',peru,'Apurimac',null).
city('Aba',nigeria,'Abia',500183).
city('Abengourou',cote_divoire,'Moyen-Comoe',null).
city('Abeokuta',nigeria,'Ogun',352735).
city('Aberdeen',united_kingdom,'Grampian',219100).
city('Aberystwyth',united_kingdom,'Ceredigion',null).
city('Abha',saudi_arabia,'Aseer',null).
city('Abidjan',cote_divoire,'Lagunes',null).
city('Abilene',united_states,'Texas',106707).
city('Aboisso',cote_divoire,'Sud-Comoe',null).
city('Abu Dhabi',united_arab_emirates,'Abu Dhabi',363432).
city('Abuja',nigeria,'Abuja',107069).
city('Acapulco',mexico,'Guerrero',515374).
city('Acarigua',venezuela,'Portuguesa',116551).
city('Accra',ghana,'Greater Accra',867459).
city('Acheng',china,'Heilongjiang',197595).
city('Achinsk',russia,'Krasnoyarskiy kray',123000).
city('Adama/Nazret',ethiopia,'Oromia',127842).
city('Adamstown',pitcairn_islands,'Pitcairn Islands',null).
city('Adana',turkey,'Adana',1047300).
city('Adapazari',turkey,'Sakarya',186000).
city('ad Damir',sudan,'ash Shamaliyah',null).
city('Ad Dammam',saudi_arabia,'Ash Sharqiyah',744321).
city('Addis Ababa',ethiopia,'Addis Ababa',2084588).
city('Adelaide',australia,'South Australia',1050000).
city('Aden',yemen,'Yemen',550744).
city('Adiyaman',turkey,'Adiyaman',128000).
city('Ado-Ekiti',nigeria,'Ekiti',156122).

my logic to achieve this task:

pop(Country,Pop) :-
    city(_,C,_,Pop),
    Country = C.

setof(P,pop(germany,P), poplist). %intend to create a list of population from a specific country
poplist([]).
poplist([_|T]) :- poplist(T).  %poplist should be the list with population from each city of germany

%I wanted to sum the entire list, so i get the total population of the germany
sum([], 0).
sum([H|T], N):-
    sum(T, X),
    N is X + H.

%once I get the total population I wanted to iteratively execute and check with the population for a specific city in the country is > 75% so to get the country listed in the output

cc(Country):-
%get the city for specific country
city(_, Country, _, Pop),
%calculate the percentage
Perc is div(Pop, sum(poplist, N)),
%see if percentage is over 75%
Perc >= 75.

Looks like my code is not working and it breaks at creating the sum(poplist, N) and even in the cc(Country) predicate definition.

I am novice in prolog and need our help here. Is my algorithm or logic make sense for the task that I wanted to achieve? How can i get the desired result?

1

There are 1 answers

5
tphilipp On BEST ANSWER

There are multiple problems in your code:

This line just defines a new fact - and nothing more.

setof(P,pop(germany,P), poplist). %intend to create a list of population from a specific country

In a similar way, your definition of poplist does not make sense for me: It just states that the empty list is a poplist, and the list [_|T] is a poplist if T is a poplist.

Your definition of sum seems to be fine, but SWI-Prolog offer built-in predicates for this (sumlist).

The line

Perc is div(Pop, sum(poplist, N)),

looks wrong; sum is a predicate; poplist is a predicate.

Moreover, you have "null" elements in the data set. Note that null is just a further atom in Prolog and you cannot sum over a list containing a non-arithmetic atom.

Here would be my solution that is not yet tested:

country(Country) :-
    city(_, Country, _, _).

has_big_city(Country) :-
    % exclude countries that have a city with unknown population
    forall(city(_, Country, _, P), dif(P, null)),
    % compute country population
    findall(P, city(_, Country, _, P), Ps),
    sumlist(Ps, Country_Population),
    % look for big city
    city(_, Country, _, City_Pop),
    Perc is City_Pop / Country_Population,
    Perc >= 0.75.


cc(Country) :-
    country(Country),
    has_big_city(Country).