Clingo: assert partial constraints - zebra-puzzle

I am trying to implement a program in clingo that solves one of those classic riddles where you have a series of assertions of facts and constraints and you have to deduce other facts. Here goes the problem:
Five men of different nationalities live in five side-by-side houses, each of a different color; they all have different jobs, a different favourite animal and favourite beverages. We know that:
The English man lives in the red house.
The Spanish man's favourite animal is the dog.
The Japanese man is a painter.
The Italian man drinks tea.
The Norwegian man lives in the first house from the left. (number_norw = 1)
The person living in the green house drinks coffee.
The green house is immediately right of the white one. (number_green = number_white + 1)
The clerk loves cats.
The salesman lives in the yellow house.
Milk is the favourite drink in the center house. (number_milk = 3)
The Norwegian's house is adjacent to the blue one. (number_norw = number_blue ± 1)
The cook likes juice.
The man living in the house next to the doctor's loves foxes.
The man who loves horses lives next door to the salesman.
The assignment is to find out who likes zebras.
So I set forth asserting:
% Number (the number of the house, 1 being the leftmost of the block, 5 the rightmost)
number(1..5).
% Color
color(red;green;white;yellow;blue).
% Nationality
nationality(english;spanish;japanese;italian;norwegian).
% Animal
animal(dog;cat;fox;horse;zebra).
% Job
job(painter;clerk;salesman;cook;doctor).
% Beverage
beverage(tea;coffee;milk;juice;coke).
% House
house(X, C, N, A, J, B) :-
number(X),
color(C),
nationality(N),
animal(A),
job(J),
beverage(B).
Now I'm stuck on asserting the constraints; how do I go about coding assertions 1. through 14.? I just need to understand the proper syntax, so if someone could please set me on the right track with one or two examples I can figure out the rest.
Thanks.
N.B. Notice I could have inferred, from 5. and 11., that the second house is the blue one because 11. number_blue = number_norw ± 1, 5. number_norw = 1, and 0 is not in the range of possible numbers, but I don't want to manually add it to the constraints because I expect clingo to figure it out itself.

One way to add the constraint for the first assertation:
% 1. The English man lives in the red house.
% S: english --> red house <==> red house OR not english
% not S: not (red house OR not english) <==> not red house AND english
% ie. it is not so, that the english man doesn't live in the red house
:- not 1 { house(X, red, english, A, J, B) :
number(X) : animal(A) : job(J) : beverage(B) }.
and as another example the seventh assertation:
% 7. The green house is immediately right of the white one.
% (number_green = number_white + 1)
:- house(NG, green, _, _, _, _), house(NW, white, _, _, _, _), NG!=NW+1.
This will however lead to long solving times and large memory requirements (gigabytes), because the grounded program (output of gringo) is massive. You can see this with gringo -t yourcode.asp. This is because the "do not care" variables _ (and X, A, J, B in the constraint for the first assertation above). Each rule will be written in at least 5*5*5*5 ways.
M. Gebser adviced me that the predicates (relations) should be kept short. The problem with this encoding of the instance is that house/6 is so long. One way to combat this would be to encode it in the following style:
house(1..5).
elem(color, red;green;white;yellow;blue).
elem(nationality, english;spanish;japanese;italian;norwegian).
...
and start from there. Now the arity of elem is only 2. When the instance is defined this way, the program becomes simpler eg. the constraints for the assertations do not need aggregates (the 1{ ... }N syntax).
:- not chosen(H, nationality, english), chosen(H, color, red).
M. Gebser also suggested that the solver (clasp) might benefit form the rule being written in the other way too:
:- not chosen(H, nationality, english), chosen(H, color, red).
:- chosen(H, nationality, english), not chosen(H, color, red).
You also need some additional restrictions, like that two different elements of the same type shouldn't be mapped to one house.
For nicer output, you can make a relation that gives the output like house/6 did.
Note that I used gringo3 and clasp2, which are not the newest versions. If you have the new clingo, there might be modifications that are needed.

Related

prolog match items from list to predicates

I'm new to prolog and trying to solve my made up following prolog's problem.
I have some people
person(john, 36).
person(jane, 3).
person(amber, 32).
person(emmy, 2).
person(clement, 37).
person(patrick, 15).
person(emilie, 20).
I have a list of compounds representing food items witch can be healthy (good).
foods([food(frechfries, _), food(apple, good), food(burger,_),
food(kiwi, good), food(banana, good), food(potato, good), food(orange, good),
food(cereal, good), food(hotdog, _), food(steak, _), food(coca, _), food(water, good)]).
I would like to match each item to one person, to distribute one and only one food to each person. To do so, I have the following rule:
distribute(P, F, Results) :- person(P, _), findall(Item, memberchk(Item, F), Results).
Unfortunately, everyone receive the first item of the list
Output
If I try to delete the used item with this rule:
distribute(P, F, Results) :- person(P, _), findall(Item, memberchk(Item, F), Results), delete(F, Item, F).
I get the same result. Anyone see what I'm missing?
Generically speaking, it sounds like you have two collections of facts and you just want to define a rule that succeeds for each unique matching pair.
The sets of facts are person and food. As I mentioned in the comment, defining the foods as a single fact with a list will be a bit awkward. I would define food in the same way you are defining person, that is, as individual facts.
person(john, 36).
person(jane, 3).
person(amber, 32).
person(emmy, 2).
person(clement, 37).
person(patrick, 15).
person(emilie, 20).
food(frechfries, _).
food(apple, good).
food(burger,_).
food(kiwi, good).
food(banana, good).
food(potato, good).
food(orange, good).
food(cereal, good).
food(hotdog, _).
food(steak, _).
food(coca, _).
food(water, good).
Now we can think about defining a match-up. You can think of it this way:
A successful match-up consists of a list of person-food pairs in which the each person and each food only appear once (are uniquely selected from the respective collections) and each person is represented.
Since we're trying to select each person and food uniquely, I'm thinking select/3 would be a good choice as a core mechanism to achieve the desired goal.
person_food_pairs(PeopleFoodPairings) :-
findall(Person, person(Person, _), People),
findall(Food, food(Food, _), Foods),
length(People, NumberOfPeople),
length(Foods, NumberOfFoods),
NumberOfPeople =< NumberOfFoods,
person_food_pairing(People, Foods, PeopleFoodPairings).
person_food_pairing([], _, []).
person_food_pairing(People, Foods, [Person-Food|RemainingPairs]) :-
select(Person, People, RemainingPeople),
select(Food, Foods, RemainingFoods),
person_food_pairing(RemainingPeople, RemainingFoods, RemainingPairs).
There are going to be a lot of combinations, so lots of solutions! I didn't see any other conditions you had which would limit this. Also, you could leave out this set of lines, and the code will still yield the same results due to the definition of person_food_pairing/2:
length(People, NumberOfPeople),
length(Foods, NumberOfFoods),
NumberOfPeople =< NumberOfFoods,
However, then the code would do a lot of unnecessary execution just to finally determine it cannot do the pairing. So these lines help determine that case early.
If, as noted in the comments, you have conditions that involve some of the person and food attributes, you'll need to carry those attributes along until you do the pairing.
person_food_pairs(PeopleFoodPairings) :-
findall(Person-Age, person(Person, Age), People), % Include age
findall(Food-Health, food(Food, Health), Foods), % Include health factor
length(People, NumberOfPeople),
length(Foods, NumberOfFoods),
NumberOfPeople =< NumberOfFoods,
person_food_pairing(People, Foods, PeopleFoodPairings).
person_food_pairing([], _, []).
person_food_pairing(People, Foods, [Person-Food|RemainingPairs]) :-
select(Person-Age, People, RemainingPeople), % Select person-age pair
select(Food-Health, Foods, RemainingFoods), % Select food-health pair
(Age < 20 -> Health == good ; true), % Condition to include
person_food_pairing(RemainingPeople, RemainingFoods, RemainingPairs).
Note the use of ==/2 here and not unification =/2. The reason for this is that you want _ not to match good. If you use unification, then Prolog will successfully unify the variable _ with the atom good. ==/2, on the other hand, checks if these two terms are truly the same and does not do unification.

Getting the Helper function to compile

I am trying to get this list to parse through a knowledge base, but I am having trouble getting the helper function to work.
The program I am trying to create, outputs a list of quests from a knowledge base which comes from at least 2 quest types, and has to have a total experience value below a cutoff.
format of allquest is:
allquest(Questtext,QuestType,ExpvalueofQuest).
allquest(water for village,Main quest, 2000).
allquest(get book for elder,fetch quest,1000).
allquest(kill 20 birds, bounty quest, 1000).
questCheck([], [_], Tot) :- Tot >= CUTOFF.
questCheck([H|T], [ListOfTypes], Tot) :- allQuests(H, Type, Exp), T2 is Tot + Exp,
questCheck(T, [Type|ListOfTypes], T2).
questCheckH([H|T]) :- allQuests(H, Type, Exp), questCheck(H, [Type], Exp).
Overall the logic of the ruleset is that it takes in a list as a parameter, iterates through that list keeping track of the exp total of each quest, Once the list has been completely iterated through it checks the total against some numbers to make sure it's 'Ok.', then it returns.
However if I input an uninstanctiated list [A], it should return list combination that fulfill my requirements.
the code should work like this if CUTOFF = 3000
?-questCheckH([A]).
water for village,get book for elder
;water for village, kill 20 birds
;get book for elder, water for village
;get book for elder, kill 20 birds, water for village
;kill 20 birds, water for village
;kill 20 birds, get book for elder, water for village
I know I need to work a T into the questCheckH with an additional predicate but am not sure how to word the predicate I need.

When a draw occurs when tracking most occurrences in a list how to find element with highest index?

lines = ["Pizza", "Vanilla","Los Angeles Pikes","Cookie Washington Tennis Festival","Water Fiesta","Watermelon"]
best= max(set(lines), key=lines.count)
print (best)
The code above returns the greatest occurrence of an element in the list, but in case there is a draw, I want it to return the element with the greatest index. So here I want Watermelon to be printed and if anything is added without a break in the tie the highest index of the draw should be printed.
I need a solution with simple basic code like that seen above and without the importing of libraries. If you could help find a good solution for this it would be really helpful.
You could add the index normalized to a value greater than the length of the array to the result of count. The normalized index will always be less than 1.0, so that it will not affect the first-order comparison, but will guarantee that there are no ties. I would use a small function to do this:
lines = ["Pizza", "Vanilla", "Los Angeles Pikes",
"Cookie Washington Tennis Festival",
"Water Fiesta", "Watermelon"]
def key(x):
return lines.count(x) + lines.index(x) / (len(lines) + 1)
best = max(set(lines), key=key)
print(best)
While your original code returned lines = "Los Angeles Pikes" in my version of Python (because of the way the hashes turned out), the new version returns "Watermelon", as expected.
You can also use a lambda, but I find that a bit harder to read:
best = max(set(lines), key=lambda x: lines.count(x) + lines.index(x) / (len(lines) + 1))

How to get count of item repetition in a list?

Hi i have a list in the following format
tweets= ['RT Find out how AZ is targeting escape pathways to further
personalise breastcancer treatment SABCS14', 'Did you know Ontario has
a special screening program for women considered high risk for
BreastCancer', 'Article Foods That Prevent BreastCancer','PRETTY
Infinity Faith Hope Breast Cancer RIBBON SIGN Leather Braided Bracelet
breastcancer BreastCancerAwareness']
I have just given a sample of list but it has a total of 8183 elemets. So now if i take 1st item in the list i have to compare that with all the other elements in the list and if 1st item appears anywhere in the list i need the count how many times it got repeated. I tried many ways possible but couldnt achieve desired result. Please help, thanks in advance.
my code
for x, left in enumerate(tweets1):
print x,left
for y, right in enumerate(tweets1):
print y,right
common = len(set(left) & set(right))
As already pointed out in comments, you can use collections.Counter to do this. The code will translate into something like below:
from collections import Counter
tweets = ['RT Find out how AZ is targeting escape pathways to further personalise breastcancer treatment SABCS14',
'Did you know Ontario has a special screening program for women considered high risk for BreastCancer',
'Article Foods That Prevent BreastCancer',
'PRETTY Infinity Faith Hope Breast Cancer RIBBON SIGN Leather Braided Bracelet breastcancer BreastCancerAwareness']
count = Counter(tweets)
for key in Count:
print key, Count[key]
Note that the Counter is essentially a dict, and so the order of the elements will not be guaranteed.

Prolog list not printing all the elements on console

I am using SWI-PROLOG version 6.6.6
I want to print all the attributes of a particular predicate type.
I have a predicate called law with arity 2.
Some of the facts are
law(borrow,'To borrow Money on the credit of the United States').
law(commerce,'To regulate Commerce with foreign Nations, and among the several States, and with the Indian Tribes').
law(unifomity,'To establish an uniform Rule of Naturalization, and uniform Laws on the subject of Bankruptcies throughout the United States').
law(money,'To coin Money, regulate the Value thereof, and of foreign Coin, and fix the Standard of Weights and Measures').
law(punishment,'To provide for the Punishment of counterfeiting the Securities and current Coin of the United States').
law(establishment,'To establish Post Offices and post Roads').
law(exclusiverights,'To promote the Progress of Science and useful Arts, by securing for limited Times to Authors and Inventors the exclusive Right to their respective Writings and Discoveries').
law(court,'To constitute Tribunals inferior to the supreme Court').
etc.
Now I want to access a law by entering its type.
Such as,
power(X) :- law(X,Y), display('\nCongress has the power : '),display(Y).
powers(ALL) :- display('\nCongress has the powers : '), law(_,Y), display('\n'), display(Y).
This works perfectly. Now, I also want the user to know what all types of laws are there so that the user can enter it as a query to get the corresponding law.
ex power(money).
For this, I made a query to get all these keywords and add them to a list and display the list.
But the list that is finally printed is not complete.
powerList(L) :- findall(X,law(X,_), L).
I use this code to get the list.
But the output on the console is
L = [borrow, commerce, unifomity, money, punishment, establishment, exclusiverights, court, piracyfelony|...].
But, there are more law types even after piracyfelony and they are not getting printed to the console. How do I get them printed?
This is a feature of Prolog's toplevel loops that tries to keep the output short.
To find out how you might change it, ask which Prolog flags your Prolog supports that have a value being a list of at least two elements:
?- current_prolog_flag(F,Options), Options = [_,_|_].
F = debugger_print_options,
Options = [quoted(true), portray(true), max_depth(10), attributes(portray), spacing(next_argument)] ;
F = toplevel_print_options,
Options = [quoted(true), portray(true), max_depth(10), spacing(next_argument)] ;
F = argv,
Options = [swipl, '-f', none] ;
false.
Now modify it accordingly:
?- length(L,10).
L = [_G303, _G306, _G309, _G312, _G315, _G318, _G321, _G324, _G327|...].
?- set_prolog_flag(toplevel_print_options,[quoted(true), portray(true), max_depth(0), spacing(next_argument)]).
true.
?- length(L,10).
L = [_G303, _G306, _G309, _G312, _G315, _G318, _G321, _G324, _G327, _G330].
(In newer versions starting with SWI 7 there is another flag value, answer_write_options.)