How can you find a certain condition that matches parameters in Prolog? - recursion

I'm new to Prolog and quite confused. We're just moving in to recursion and members. I have the task to find different combinations of fast food given the type, calories, and price:
burger 450 $5
fries 250 $2
shake 500 $3
salad 150 $7
I created a rule:
findfood(Calories, Price, Burger, Fries, Shake, Salad) :-
member(Burger, [0,1]),
...,
C is Burger*450 + Fries*250 + ...,
Price is Burger*5 + Fries*2 + ...,
C =< Calories.
where '...' indicates a continuation of the previous to the end of the list of food items. Essentially, you can purchase 1 of each item and indicate such with a 0 or a 1 (this is all part of the specifications).
I need to find the most expensive food combination less than or equal to a certain caloric amount. I am allowed to create multiple rules to do this. It should be something like:
|?- most_expensive(1000, Price, Burger, Fries, Shake, Salad)
and it will return the most expensive combination of food for 1000 calories. I know I'll need to do some sort of recursive comparison, but I'm not sure how to proceed. For the record, I understand recursion pretty well, just not Prolog. Can anyone perhaps explain how I might accomplish this?

So, you elided some of the code, but I gather this is what you have:
findfood(Calories, Price, Burger, Fries, Shake, Salad) :-
member(Burger, [0,1]),
member(Fries, [0,1]),
member(Shake, [0,1]),
member(Salad, [0,1]),
Calories is Burger * 450 + Fries * 250 + Shake * 500 + Salad * 150,
Price is Burger * 5 + Fries * 2 + Shake * 3 + Salad * 7.
This seems sensible, if labor-intensive. Now you can easily enumerate all of the possibilities following #mbratch's advice:
all_combos(Combinations) :-
setof((C,P,B,F,Sh,Sa), findfood(C,P,B,F,Sh,Sa), Combinations).
You can also abuse Prolog to get the solution you want from this:
most_expensive_under(MaximumCalories, Calories, Price, Burgers, Fries, Shakes, Salads) :-
all_combos(Combos),
member((Calories, Price, Burgers, Fries, Shakes, Salads), Combos),
Calories =< MaximumCalories,
\+ (member((Calories2, Price2, _, _, _, _), Combos),
Calories2 =< MaximumCalories,
Price2 > Price).
This declares that the most expensive option is the one for which there is no other option satisfying the maximum calorie constraint with a greater price. Trying it seems to succeed:
?- most_expensive_under(1000, Calories, Price, Burgers, Fries, Shakes, Salads).
Calories = 850,
Price = 14,
Burgers = Fries, Fries = Salads, Salads = 1,
Shakes = 0 ;
false.
Bear in mind, this kind of solution is O(N^2). I bring it up really only to illustrate the power of unification—it's not a great idea, performance-wise. A better idea would be to use setof/3, which sorts its results, as #mbratch suggests, or library(aggregate), which I've never used but hear good things about.

Related

How to do only 2 recursive calls in Prolog?

isTallerThan2(X,Y) :- tallerThan(X,Y).
isTallerThan2(X,Y) :- tallerThan(X,Z), isTallerThan2(Z,Y).
Where I want to find where someone is taller than 2 people.
If I have lots of relations where person X is taller than person Y like this tallerThan(X,Y)and if person b is taller than person a and person c is taller than person b... then I want to find all persons c but stop there and not find persons d,e,f... etc.
Since you have your database of tallerThan/2 facts, and you trust it (that is, tallerThan/2 is a DAG), you can write your rule as simple as
isTallerThan2(X,_Y) :- tallerThan(X,A),tallerThan(X,B),A\==B.
As per your comment, the second argument isn't used, so better to write like
isTallerThan2(X) :- tallerThan(X,A),tallerThan(X,B),A\==B.
isTallerThan2(X,_Y) :- isTallerThan2(X).
Since you are not interested in the smaller Persons, you need to store only the larger person. There are two ways to build it: one is to hardcode two relations, the other one is to recursively code it with a counter variable.
Version one: Z is taller than Y, Y is taller than someone.
tallerThan2(Z):-
tallerThan(Y,_),
tallerThan(Z,Y).
For the fact base
tallerThan(marge, homer).
tallerThan(homer, bart).
tallerThan(bart, lisa).
tallerThan(lisa, maggie).
tallerThan(abe, maggie).
tallerThan(marge, abe).
the output is
?- tallerThan2(P).
P = marge ;
P = homer ;
P = bart ;
P = marge ;
false.
The second way is to count the number of relations. You know of person Y that he or she is taller as at least NN people. If person Z is taller than Y then Z is taller than at least N = NN+1 people.
taller(Y,1) :-
tallerThan(Y,_).
taller(Z,N) :-
tallerThan(Z,Y),
taller(Y,NN),
N is NN+1.
Now the test:
?- taller(P,2).
P = marge ;
P = homer ;
P = bart ;
P = marge ;
false.
Is the same. marge appears twice in the list since she is taller than homer and taller than abe; both are taller than maggie.

How does one approach this challenge asked in an Amazon Interview?

I am struggling optimising this past amazon Interview question involving a DAG.
This is what I tried (The code is long and I would rather explain it)-
Basically since the graph is a DAG and because its a transitive relation a simple traversal for every node should be enough.
So for every node I would by transitivity traverse through all the possibilities to get the end vertices and then compare these end vertices to get
the most noisy person.
In my second step I have actually found one such (maybe the only one) most noisy person for all the vertices of the traversal in step 2. So I memoize all of this in a mapping and mark the vertices of the traversal as visited.
So I am basically maintaining an adjacency list for the graph, A visited/non visited mapping and a mapping for the output (the most noisy person for every vertex).
In this way by the time I get a query I would not have to recompute anything (in case of duplicate queries).
The above code works but since I cannot test is with testcases it may/may not pass the time limit. Is there a faster solution(maybe using DP) to this. I feel I am not exploiting the transitive and anti symmetric condition enough.
Obviously I am not checking the cases where a person is less wealthy than the current person. But for instance if I have pairs like - (1,2)(1,3)(1,4)...etc and maybe (2,6)(2,7)(7,8),etc then if I am given to find a more wealthy person than 1 I have traverse through every neighbor of 1 and then the neighbor of every neighbor also I guess. This is done only once as I store the results.
Question Part 1
Question Part 2
Edit(Added question Text)-
Rounaq is graduating this year. And he is going to be rich. Very rich. So rich that he has decided to have
a structured way to measure his richness. Hence he goes around town asking people about their wealth,
and notes down that information.
Rounaq notes down the pair (Xi; Yi) if person Xi has more wealth than person Yi. He also notes down
the degree of quietness, Ki, of each person. Rounaq believes that noisy persons are a nuisance. Hence, for
each of his friends Ai, he wants to determine the most noisy(least quiet) person among those who have
wealth more than Ai.
Note that "has more wealth than"is a transitive and anti-symmetric relation. Hence if a has more wealth
than b, and b has more wealth than c then a has more wealth than c. Moreover, if a has more wealth than
b, then b cannot have more wealth than a.
Your task in this problem is to help Rounaq determine the most noisy person among the people having
more wealth for each of his friends ai, given the information Rounaq has collected from the town.
Input
First line contains T: The number of test cases
Each Test case has the following format:
N
K1 K2 K3 K4 : : : Kn
M
X1 Y1
X2 Y2
. . .
. . .
XM YM
Q
A1
A2
. . .
. . .
AQ
N: The number of people in town
M: Number of pairs for which Rounaq has been able to obtain the wealth
information
Q: Number of Rounaq’s Friends
Ki: Degree of quietness of the person i
Xi; Yi: The pairs Rounaq has noted down (Pair of distinct values)
Ai: Rounaq’s ith friend
For each of Rounaq’s friends print a single integer - the degree of quietness of the most noisy person as required or -1 if there is no wealthier person for that friend.
Perform a topological sort on the pairs X, Y. Then iterate from the most wealthy down the the least wealthy, and store the most noisy person seen so far:
less wealthy -> most wealthy
<- person with lowest K so far <-
Then for each query, binary search the first person with greater wealth than the friend. The value we stored is the most noisy person with greater wealth than the friend.
UPDATE
It seems that we cannot rely on the data allowing for a complete topological sort. In this case, traverse sections of the graph that lead from known greatest to least wealth, storing for each person visited the most noisy person seen so far. The example you provided might look something like:
3 - 5
/ |
1 - 2 |
/ |
4 --
Traversals:
1 <- 3 <- 5
1 <- 2
4 <- 2
4 <- 5
(Input)
2 1
2 4
3 1
5 3
5 4
8 2 16 26 16
(Queries and solution)
3 4 3 5 5
16 2 16 -1 -1

Need a solution for designing my database that has some potential permutation complexity?

I am building a website where I need to make sure that the number of "coins" and number of "users" wont kill the database if increases too quickly. I first posted this on mathematica (thinking its a maths website, but found it it's not). If this is the wrong place, please let me know and I'll move it accordingly. However, it does boil down to solving a complex problem: will my database explode if the users increase too quickly?
Here's the problem:
I am trying to confirm if the following equations would work for my problem. The problem is that i have USERS (u) and i have COINS (c).
There are millions of different coins.
One user may have the same coin another user has. (i.e. both users have coin A)
Users can trade coins with each other. (i.e. Trade coin A for coin B)
Each user can trade any coin with another coin, so long as:
they don't trade a coin for the same coin (i.e. can't trade coin A for another coin A)
they can't trade with themselves (i.e. I can't offer my own Coin A for my own Coin B)
So, effectively, there are database rows stored in the DB:
trade_id | user_id | offer_id | want_id
1 | 1 | A | B
2 | 2 | B | C
So in the above data structure, user 1 wants coin A for coint B, and user 2 wants coin B for coin C. This is how I propose to store the data, and I need to know that if I get 1000 users, and each of them have 15 coins, how many relationships will get built in this table if each user offers each coin to another user. Will it explode exponentially? Will it be scalable? etc?
In the case of 2 users with 2 coins, you'd have user 1 being able to trade his two coins with the other users two coins, and vice versa. That makes it 4 total possible trade relationships that can be set up. However, keeping in mind that if user 1 offers A for B... user 2 can't offer B for A (because that relationship already exists.
What would the equation be to figure out how many TRADES can happen with U users and C coins?
Currently, I have one of two solutions, but neither seem to be 100% right. The two possible equations I have so far:
U! x C!
C x C x (U-1) x U
(where C = coins, and U = users);
Any thoughts on getting a more exact equation? How can I know without a shadow of a doubt, that if we scale to 1000 users with 10 coins each, that this table won't explode into millions of records?
If we just think about how many users can trade with other users. You could make a table with the allowable combinations.
user 1
1 | 2 | 3 | 4 | 5 | 6 | ...
________________________________
1 | N | Y | Y | Y | Y | Y | ...
user 2 2 | Y | N | Y | Y | Y | Y | ...
3 | Y | Y | N | Y | Y | Y | ...
The total number of entries in the table is U * U, and there are U N's down the diagonal.
Theres two possibilities depending on if order matters. Is trade(user_A,user_B) is the same as trade(user_B,user_A) or not? If order matters the same the number of possible trades is the number of Y's in the table which is U * U - U or (U-1) * U. If the order is irrelevant then its half that number (U-1) * U / 2 which are the Triangular numbers. Lets assume order is irrelevant.
Now if we have two users the situation with coins is similar. Order does matter here so it is C * (C-1) possible trades between the users.
Finally multiply the two together (U-1) * U * C * (C-1) / 2.
The good thing is that this is a polynomial roughly U^2 * C^2 so it will not grow to quickly. This thing to watch out for is if you have exponential growth, like calculating moves in chess. Your well clear of this.
One of the possibilities in your question had U! which is the number of ways to arrange U distinct objects into a sequence. This would have exponential growth.
There are U possible users and there are C possible coins.
Hence there are OWNS = CxU possible "coins owned by an individual".
Hence there are also OWNS "possible offerings for a trade".
But a trade is a pair of two such offerings, restricted by the rule that the two persons acting as offerer cannot be the same, and neither can the offered coin be the same. So the number of candidates for completing a "possible offering" to form a "complete trade" is (C-1)x(U-1).
The number of possible ordered pairs that form a "full-blown trade" is thus
CxUx(C-1)x(U-1)
And then this is still to be divided by two because of the permutation issue (trades are a set of two (person,coin) pairs, not an ordered pair).
But pls note that this sort of question is actually an extremely silly one to worry about in the world of "real" database design !
I need to know that if I get 1,000 users, and each of them have 15 coins, how many relationships will get built in this table if each user offers each coin to another user.
The most that can happen is all 1,000 users each trade all of their 15 coins, for 7,500 trades. This is 15,000 coins up for trade (1,000 users x 15 coins). Since it takes at least 2 coins to trade, you divide 15,000 by 2 to get the maximum number of trades, 7,500.
Your trade table is basically a Cartesian product of the number of users times the number of coins, divided by 2.
(U x C) / 2
I'm assuming users aren't trading for the sake of trading. That they want particular coins and once they get the coins, won't trade again.
Also, most relational databases can handle millions and even billions of rows in a table.
Just make sure you have an index on trade id and on user id, trade id in your Trade table.
The way I understand this is that you are designing an offer table. I.e. user A may offer coin a in exchange for coin b, but not to a specific user. Any other user may take the offer. If this is the case, the maximum number of offers is proportional to the number of users U and the square of the number of coins C.
The maximum number of possible trades (disregarding direction) is
C(C-1)/2.
Every user can offer all the possible trades, as long as every user is offering the trades in the same direction, without any trade being matched. So the absolute maximum number of records in the offer table is
C(C-1)/2*U.
If trades are allowed between more than two user the number decreases above half that though. E.g. if A offers a for b, B offers b for c and C offers c for a. Then a trade could be accomplished in a triangle by A getting b from B, B getting c from C and C getting a from A.
The maximum number of rows in the table can then be calculated by splitting the C coins into two groups and offering any coin it the first group in exchange any coin in the second. We get the maximum number of combination if the groups are of the same size, C/2. The number of combinations is
C/2*C/2 = C^2/4.
Every user may offer all these trades without there being any possible trade. So the maximum number of rows is
C^2/4*U
which is just over half of
C(C-1)/2*U = 2*(C^2/4*U) - C/2*U.

Prolog Recursion skipping same results

My code runs but the problem is it shows the same results more than once. Here's my code:
disease(hiv,[sore_throat,headache,fever,rash]).
disease(pregnancy,[fatigue,vomiting,light_headedness,increased_waistline]).
disease(flu,[fatigue,fever,tiredness,nasal_discharge]).
diagnose([], []).
diagnose(Name, [H|T]) :-
disease(The_Disease, Symptoms),
member(H, Symptoms),
write(Name), write(' has/is '), writeln(The_Disease),
diagnose(Name, T).
member(X,[X|_]).
member(X,[_|T]):-
member(X,T).
Result when executed in prolog:
?- diagnose(kevin,[sore_throat,fatigue,tiredness,rash]).
kevin has/is hiv
kevin has/is pregnancy
kevin has/is flu
kevin has/is hiv
kevin has/is flu
kevin has/is flu
kevin has/is hiv
false.
How do I avoid that same results? I tried using other method I found here:
filter_doubles([], []).
filter_doubles([X|L], Result) :-
(memberchk(X,L) ->
filter_doubles(L, Result)
;
filter_doubles(L, Result0),
Result = [X|Result0]
).
But I failed to apply it to my code. Help please.
Your program has a pure core - or to stick to medical terms - a pure heart, but this is intertwined with cancerous I/O tissue! In this manner doing it right is very difficult, if not impossible. For example, as a minor error, your program fails for kevin. But you probably meant it to succeed. On the other hand, you will succeed for the mysterious mister []! Who is that?
So lets separate the pure from the impure!
The pure part in your program is about relating a list of symptoms to possible diagnoses. Your working assumption is that if there is one symptom which is part of the indications for a malady, we will diagnose that malady - just to be sure. So why not call this symptoms_diagnosis/2?
symptoms_diagnosis(Symptoms, Diagnosis) :-
member(Symptom, Symptoms),
disease(Diagnosis, Indications),
member(Symptom, Indications).
?- symptoms_diagnosis([sore_throat,fatigue,tiredness,rash], Diagnosis).
Diagnosis = hiv
; Diagnosis = pregnancy
; Diagnosis = flu
; Diagnosis = flu
; Diagnosis = hiv
; false.
Note that even without any further ado, we have less redundant solutions than in your original program. So how to get rid of the remaining redundant solutions? This does the trick:
?- setof(t,symptoms_diagnosis([sore_throat,fatigue,tiredness,rash], Diagnosis),_).
Diagnosis = flu
; Diagnosis = hiv
; Diagnosis = pregnancy.
So whenever you get redundant solutions, simply wrap a setof(t, ..., _) around your goal.
You can use that whenever the answers are ground answers. That is, there is no variable left in the answer.
Maybe you prefer to get the diagnosis in a list of its own?
?- setof(Diagnosis,symptoms_diagnosis([sore_throat,fatigue,tiredness,rash],Diagnosis),Diagnoses).
Diagnoses = [flu,hiv,pregnancy].
So, now we are ready for the Princeton-Plainsboro Teaching Hospital! It is only superstition if Dr. House will not accept Prolog's diagnosis!
For the impure part, please look at #Mog's approach.
Alternatively, you can write :
disease(hiv,[sore_throat,headache,fever,rash]).
disease(pregnancy,[fatigue,vomiting,light_headedness,increased_waistline]).
disease(flu,[fatigue,fever,tiredness,nasal_discharge]).
diagnose(Name, Symptoms) :-
findall(D, (disease(D, S), intersection(S, Symptoms, I), I \== []), MayGot),
atomic_concat(Name, ' has/is ', Start),
maplist(atomic_concat(Start), MayGot, Temp),
maplist(writeln, Temp).
But if you're trying to learn Prolog it's not a good idea since it's more functionnal and less Prolog-ish, thought I'd mention this possibility anyway !
You have to remember what diseases you already collected when checking the symptoms. You need to collect (aggregate) the diseases in a list, and check whether a disease is already present in the list before adding it. You can then print the list at the end or print out each new disease as it is added to the list.
I would implement it this way:
diagnose(Name, Symptoms) :- diagnose0(Name, Symptoms, []).
diagnose0(Name, [], Diseases) :-
print_diseases(Name, Diseases).
diagnose0(Name, [H|T], DIn) :-
disease(Disease, Symptoms),
member(H, Symptoms),
% you may want to add a cut here to avoid choicepoints
(
member(Disease, DIn)
->
diagnose0(Name, T, DIn)
;
DOut = [Disease|DIn],
diagnose0(Name, T, DOut)
).
print_diseases(_Name, []).
print_diseases(Name, [H|T]) :-
write(Name), write(' has/is '), writeln(H),
print_diseases(Name, T).
The disease/2 facts are as in your code.
This gives:
?- diagnose(kevin, [sore_throat, fatigue, tiredness, rash]).
kevin has/is flu
kevin has/is pregnancy
kevin has/is hiv
Yes (0.00s cpu, solution 1, maybe more)
The next step then would obviously be to find a way to express that some diagnoses represent alternatives for a given symptom, and choose between these different alternatives. With the symptoms listed in the query, Kevin should have flu and HIV, but I doubt that pregnancy is a correct diagnosis for Kevin. This is related to the comment about a cut that I inserted in the second clause of diagnose/3: without the cut, you can get more than one solution, each representing a different set of diseases that match the set of symptoms. If you add a cut, you only get the first solution (including pregnancy). The second solution only contains flu and HIV.
BTW, member/2 is a built-in predicate, so you don't need to define your own.

Ideas for optimization algorithm for Fantasy Football

So, this is a bit different than standard fantasy football. What I have is a list of players, their average "points per game" (PPG) and their salary. I want to maximize points per game under the constraint that my team does not exceed a salary cap. A team consists of 1 QB, 1 TE, 3 WRs, and 2 RBs. So, if we have 15 of each position we have 15X15 X(15 c 3)X(15 c 2) = 10749375 possible teams.
Pretty computationally complex. I can use a bit of branch and bound i.e. once a team has surpassed the salary cap I can trim the tree, but even with that the algorithm is still pretty slow. I tried another option where I used a "genetic algorithm" i.e. made 10 random teams, picked the best one and "mutated" it (randomly changing some of the players) into another 10 teams and then picked of those and then looped through a bunch of times until the points per game of the "best team" stopped getting better.
There must be a better way to do this. I'm not a computer scientist and I've only taken an intro course in algorithmics. Programmers - what are your thoughts? I have a feeling that some sort of application of dynamic programming could help.
Thanks
I think a genetic algorithm, intelligently implemented, will yield an acceptable result for you. You might want to use a metric like points per salary dollar rather than straight PPG to decide the best team. This way you are inherently measuring value added. Also, you should consider running the full algorithm/mutation to satisfactory completion numerous times so that you can identity what players consistently show up in the final outcomes. These players then should be valued above others.
Of course the problem with the genetc approach Is that you need a good mutation algorithm and that is highly personal for how you want to implement it.
Take i as the current number of players out of n players and j to be the current remaining salary that is left. Take m[i, j] to be the dynamic set of solutions.
Then m[i, 0] = 0, m[0, j] = 0
and
m[i, j] = m[i - 1, j] if salary for player i is greater than j
else
m[i, j] = max ( m[i - 1, j], m[i - 1, j - salary of player i] + PPG of player i)
Sorry that I don't know R but I'm good with algorithms so I hope this helps.
A further optimization you can make is that you really only need 2 rows of m[i, j] because the DP solution only uses the current row and the last row (you can save memory this way)
First of all, the variation you have provided should not be right. Best way to build team is limit positions by limited plus there is absolutely no sense of moving 3 similar positions players between themselves.
Christian Ronaldo, Suarez and Messi will give you the equal sum of fantasy points in any line-up, like:
Christian Ronaldo, Suarez and Messi
or
Suarez, Christian Ronaldo and Messi
or
Messi, Suarez, Ronaldo
First step - simplify the variation possibility.
Next step - calculate the average price, and build the team one by one by adding player with lower salary but higher price. When reach salary limit, remove expensive one and add cheaper but with same fantasy points - and so on. Don't build the variation, value the weight of each player by combination of salary and fantasy points.
Does this help? It sets up the constraints and maximises points.
You could adapt to get data out of excel
http://pena.lt/y/2014/07/24/mathematically-optimising-fantasy-football-teams
14/07/24/mathematically-optimising-fantasy-football-teams

Resources