Prolog regarding list manipulation - list

statement:
value(engine,2000).
value(frame,605).
vehicle(motorbike,[engine,frame]).
how to write prolog predicate total(X). X is your total sum for motorbike.
I was unable to relate value of engine=2000 plus value of frame=605 that should return answer 2605 if i consult total(motorbike).

aggregation it's your friend:
total(Kind, X) :-
vehicle(Kind, Parts),
aggregate(sum(Price), Part^(member(Part, Parts), value(Part, Price)), X).

Here's a version that does the summation explicitly if you don't have the aggregate predicate that CapelliC shows:
% This says total is sum of the parts
total( Item, Amt ) :-
vehicle( Item, PartList ),
sum_parts( PartList, 0, Amt ).
% This says the sum of the parts is the sum of current part in list plus the sum
% of the rest
sum_parts( [Part|PartList], Acc, Amt ) :-
value( Part, PartAmt ), % This statement will relate the part to its price for you
Acc1 is Acc + PartAmt, % This will accumulate the price to the running total
sum_parts( PartList, Acc1, Amt ).
sum_parts( [], Amt, Amt ).

Related

How to find a list in prolog?

Previously I wrote the predicate, reach(Departure, Arrivals) to find
all points I can get into from the Departure point. How I can find a
list of names of departure points from which I can get to a given
point arrivals?
For example ?- list(krum, Departure).
Answer: Departure = [uzhorod].
This is my code:
reachable(D, D, _).
reachable(Departure, Arrival, Visited) :-
trip(_, Departure, Point, _),
\+ member(Point, Visited),
reachable(Point, Arrival, [Point|Visited]).
reachable(Departure, Arrival) :-
reachable(Departure, Arrival, [Departure]).
reach(Departure, Arrivals):-
setof(
Arrival,
reachable(Departure, Arrival),
Arrivals
),
Arrivals \= [Departure].
This is my facts:
trip(01, kuiv, odessa, 1500).
trip(02, kuiv, lviv, 700).
trip(08, lviv, zaporizhya, 700).
trip(03, uzhorod, krum, 6000).
trip(04, vunohradiv, odessa, 2540).
trip(05, ternopil, kuiv, 3800).
trip(06, zaporizhya, donetsk, 900).
trip(07, lytsk, mariupol, 7500).
trip(Id, Departure, Arrivals, Price)
This is my output:
For example ?- reach(kuiv, Arrivals).
Answer: Arrivals = [donetsk, kuiv, lviv, odessa, zaporizhya]
As #TA_intern points out we just need to flip arguments in the reach:
inverse_reach(Arrival, Departures) :-
setof(
Departure,
reachable(Departure, Arrival),
Departures
).

prolog how to sort through a list of names and find the highest value among those names

I am trying to sort through a list of deaths and find the county with the highest amount of deaths. what i have working so far is - when given a List, the program will correctly display the highest number of deaths and and the lowest number of deaths. What I want it to output is the name of the county assosiated with that death count. for example, right now my program:
county(a).
county(b).
countyDeaths(a,45).
countyDeaths(b,0).
start :-
max_deaths([4,0,0,19,1,3,5,45,14,2,27,14], MaxNumberDeaths),
min_deaths([4,0,0,19,1,3,5,45,14,2,27,14], MinNumberDeaths),
show_results(MaxNumberDeaths, MinNumberDeaths).
max_deaths([Head|Tail], Max) :-
max_deaths(Tail, Value),
Head > Value,
Max is Head.
max_deaths([Head|Tail], Max) :-
max_deaths(Tail, Value),
Head =< Value,
Max is Value.
max_deaths([], 0).
min_deaths([Head|Tail], Min) :-
min_deaths(Tail, Value),
Head < Value,
Min is Head.
min_deaths([Head|Tail], Min) :-
min_deaths(Tail, Value),
Head >= Value,
Min is Value.
min_deaths([], 0).
show_results(MaxNumberDeaths, MinNumberDeaths) :-
write("The max number of deaths is: "),
writeln(MaxNumberDeaths),
write("The min number of deaths is: "),
writeln(MinNumberDeaths).
outputs:
?- start.
The max number of deaths is: 45
The min number of deaths is: 0
which is correct - but I want it to output:
The county with the highest amount of deaths is county "a" with a total of 45 deaths.
When I tried to put the counties into the list in order to be sorted through, it wouldn't allow that data type to be put into the list.
Is there anyway for me to allow the list to find the number associated with the county name?
Assuming that your countyDeaths/2 is a set of facts relating county name to the number of deaths in that county, you could do something like this:
county_deaths(a,45).
county_deaths(b,0).
% . . .
county_deaths(z,19).
start :-
findall( N , county_deaths(_,N), [N|Ns] ) ,
min_max( Ns , N , N , Min, Max ) ,
display_max(Max),
display_min(Min)
.
min_max( [] , Min , Max , Min , Max ) .
min_max( [N|Ns] , X , Y , Min , Max ) :- N < X , !, min_max(Ns,N,Y,Min,Max) .
min_max( [N|Ns] , X , Y , Min , Max ) :- N > Y , !, min_max(Ns,X,N,Min,Max) .
min_max( [_|Ns] , X , Y , Min , Max ) :- min_max(Ns,X,Y,Min,Max) .
% multiple counties could have the same number of deaths, so
% we use findall/3 to enumerate all counties with the specified
% number of deaths.
display_max(N) :-
findall(C,county_deaths(C,N),Cs) ,
writeln(max_deaths:Cs:N)
.
display_min(N) :-
findall(C,county_deaths(C,N),Cs) ,
writeln(min_deaths:Cs:N)
.

Is there a non-hack way to print continued fractions in SymPy with integers without evaluation?

I would like to see continued fractions with integers displayed in that form with SymPy, but I cannot seem to make SymPy comply. I found this Stack Overflow question and answer very useful (see farther below), but cannot reach my target goal here:
This is the continued fraction expansion of $\frac{13}{5}$. A common notation for this expansion is to give only the boxed terms as does SymPy below, i.e., $[2,1,1,2]$ from the SymPy continued_fraction_iterator:
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
print( Rat_13_5 )
Rat_13_5 = list(continued_fraction_iterator(Rational(13, 5)))
( Rat_13_5 )
print( Rat_13_5 )
With output [2, 1, 1, 2].
Pg 37 of the Sympy manual release 1.5 Dec 9, 2019 gives a code snippet to print such an expanded fraction list:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr += i
expr = 1/expr
return l[0] + expr
If you invoke list_to_frac with the Rat_13_5 continued fraction expansion list, SymPy takes off and evaluates it:
print( list_to_frac( Rat_13_5 ) )
with output 13/5
If you use a list of symbols instead, then list_to_frac prints the desired continued fraction, e.g.,
n1, n2, n3, n4, n5, n6, n7, n8, n9 = symbols('n1:10')
cont_frac_list = [n2, n1, n1, n2]
contfrac12201015 = list_to_frac( [n2,n1,n1,n2] )
contfrac122010154
Which produces the desired (I am working in a JupyterLab environment so am actually obtaining typset LaTeX output throughout):
n2 + 1/(n1 + 1/(n1 + 1/n2))
I rewrote list_to_frac to use the UnevaluatedExpr facility presented by Francesco in the StackOverflow question I cited earlier:
def list_to_frac_noEval(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = UnevaluatedExpr(expr + i)
expr = UnevaluatedExpr( 1/expr )
return l[0] + expr
Invoking list_to_frac_noEval on the $\frac{13}{5}$ expansion list:
list_to_frac_noEval( [2,1,1,2] )
I obtain output
2 + (1 + (1 + 2**(-1))**(-1))**(-1)
Some folks use that notation (so I wanted to share list_to_frac_noEval in any case, that being superior to ending up with an evaluated single rational if you want to see the continued fraction), for example Roger Penrose in section $\unicode{x00A7}3.2$ of The Road to Reality (2004), but I still find it annoying that I cannot obtain the explicit continued fraction format when using integers instead of symbols.
I experimented with substituting in integers for symbols with evaluate=False, using both the subs method and the Subs function, looked at various combinations of sympify and srepr and parse_expr with evaluate=False, , but cannot persuade SymPy 1.4 to print the explicit fraction form that I obtain with list_to_frac operating on symbol arguments. Is there a way to accomplish this short of modifying SymPy code or special casing a particular set of numbers?
You can construct the expression explicitly passing evaluate=False to each part of the expression tree:
def list_to_frac(l):
expr = Integer(0)
for i in reversed(l[1:]):
expr = Add(i, expr, evaluate=False)
expr = Pow(expr, -1, evaluate=False)
return Add(l[0], expr, evaluate=False)
That gives:
In [2]: nums = list(continued_fraction_iterator(Rational(13, 5)))
In [3]: nums
Out[3]: [2, 1, 1, 2]
In [4]: list_to_frac(nums)
Out[4]:
1
───────────── + 2
1
───────── + 1
1
───── + 1
0 + 2
It looks like it's the wrong way around but that's just the way the printing works with default settings:
In [5]: init_printing(order='old')
In [6]: list_to_frac(nums)
Out[6]:
1
2 + ─────────────
1
1 + ─────────
1
1 + ─────
0 + 2
You can trigger evaluation with doit:
In [7]: _.doit()
Out[7]: 13/5

prolog : protein to RNA reverse translation

i want to show all possible probabilities of RNA sequence in a protein sequence
annexin is the name of the protein.
fact:
protein(annexin,[phe,leu,gly]).
code('phe') -> codon('UUU','UUC')
code('leu') -> codon('UUA','UUG')
code('gly') -> codon('GGC','GGU')
rules:
rna(X):-
protein(X,[A,B,C].
(i dont know how to permute the triplet codon)
query:
rna(annexin)
result:
UUU,UUA,GGC
UUU,UUG,GGC
UUU,UUA,GGU
UUC,UUA,GGC
...
...
I think the representation of code/codon has to be explicit, then
protein(annexin,[phe,leu,gly]).
code(phe, ['UUU','UUC']).
code(leu, ['UUA','UUG']).
code(gly, ['GGC','GGU']).
rna(X, R) :- protein(X, LC), maplist(code_p, LC, R).
code_p(C, R) :- code(C, L), member(R, L).
yields
?- rna(annexin, C).
C = ['UUU', 'UUA', 'GGC'] ;
C = ['UUU', 'UUA', 'GGU'] ;
C = ['UUU', 'UUG', 'GGC'] ;
C = ['UUU', 'UUG', 'GGU'] ;
C = ['UUC', 'UUA', 'GGC'] ;
C = ['UUC', 'UUA', 'GGU'] ;
C = ['UUC', 'UUG', 'GGC'] ;
C = ['UUC', 'UUG', 'GGU'].
1)
code('phe') -> codon('UUU','UUC')
is not an usual fact, I will supposse you mean something like:
code('phe',codon('UUU','UUC')).
2)
You do not need evaluate all possible answers, prolog does it by you:
rna(X) :-
protein(X,[CA,CB,CC]),
( code(CA,codon(DA,_)); code(CA,codon(_,DA)) ),
( code(CB,codon(DB,_)); code(CB,codon(_,DB)) ),
( code(CC,codon(DC,_)); code(CC,codon(_,DC)) ),
format('~w ~w ~w~n', [DA, DB, DC] ),
fail.
(if you need some postprocess of the result, remove the format&fail and use setof/bagof to store all them in a list).

Recursively Assigning One List Element to Another in Prolog

This is a homework assignment and my first experience with Prolog. My goal is to create a list of Assignments from a list of people and a list of tasks. If a person has the letter identifier which matches the tasks then that persons ID and the Tasks ID are matched up and placed in a list of Assignments. My function prints out a list but it does not look like it is comparing all the elements. A sample input: schedule([p1,p2,p3],[t1,t2],Result). A sample output would look like [[p1,t1],[p2,t2][p3,t1],[p3,t2]].
What I have so far:
%%
%% person(ID, TASK_CAPABILITIES, AVAILABLE_HOURS)
%%
%% How many hours each person has available and what classes of tasks they
%% are capable of performing.
%%
person(p1, [c,a], 20).
person(p2, [b], 10).
person(p3, [a,b], 15).
person(p4, [c], 30).
%%
%% task(ID, REQUIRED_HOURS, TASK_CLASS)
%%
%% How long each task requires and what class it falls under.
%%
task(t1, a, 5).
task(t2, b, 10).
task(t3, c, 15).
task(t4, c, 10).
task(t5, a, 15).
task(t6, b, 10).
%test arithmetic functions
add(X, Y, Z) :- Z is X + Y.
subtract(X,Y,Z) :- Z is X - Y.
schedule([],[],[]).
schedule(People,
[Task|OtherTasks],
[[PersonId, TaskId]|RestOfAssignments]):-
member(PersonId, People),
person(PersonId, PersonCapabilities,_),
member(TaskId, [Task|OtherTasks]),
task(TaskId, TaskType,_),
member(TaskType, PersonCapabilities),
schedule( _, OtherTasks, RestOfAssignments).
My reasoning behind what I wrote was that the list of People would be compared to each task, then that task would be replaced by the next task and the comparison would repeat. What I see in the trace of this function instead is that the tasks are being removed from the list but are only compared to the first two People. My question is how can I get the schedule function to check the full list of people for each task?
Your problem seems ill specified, and you are simplifying too much... the code should keep into account hours availability as well as memberships. Ignoring this problem, select/3 instead of member/2 could help to model a naive solution:
schedule([],_,[]).
% peek a suitable task for PersonId
schedule([PersonId|People], Tasks, [[PersonId, TaskId]|RestOfAssignments]):-
select(TaskId, Tasks, RestTasks),
person(PersonId, PersonCapabilities,_),
task(TaskId, TaskType,_),
memberchk(TaskType, PersonCapabilities),
schedule(People, RestTasks, RestOfAssignments).
% if no suitable task for PersonId
schedule([_PersonId|People], Tasks, Assignments):-
schedule(People, Tasks, Assignments).
yields these solutions
?- schedule([p1,p2,p3],[t1,t2],Result).
Result = [[p1, t1], [p2, t2]] ;
Result = [[p1, t1], [p3, t2]] ;
Result = [[p1, t1]] ;
Result = [[p2, t2], [p3, t1]] ;
Result = [[p2, t2]] ;
Result = [[p3, t1]] ;
Result = [[p3, t2]] ;
Result = [].