So I have a list that looks like this:
[
["p1", "p2", "100", "Storgatan"],
["p1", "p3", "200", "Lillgatan"],
["p2", "p4", "100", "Nygatan"],
["p3", "p4", "50", "Kungsgatan"],
["p4", "p5", "150", "Kungsgatan"]
]
The elements in each nested list represent (in order):
1st element = Start Point
2nd element = End Point
3rd element = Distance
4th element = Street Name.
I have to now write a predicate which figures out which street is the shortest and which street is the longest, along with their respective (summed up) distances.
For example the final output should look something like this:
Longest street: Kungsgatan, 200
Shortest street: Storgatan, 100
I don't really understand why the start and end points are relevant information here. My current idea is to collect all the unique street names, put them in a separate list along with a counter for each street that starts at zero and then use that list to accumulate all of the distances for each separate street.
Something like:
create_sum_list([
["p1", "p2", "100", "Storgatan"],
["p1", "p3", "200", "Lillgatan"],
["p2", "p4", "100", "Nygatan"],
["p3", "p4", "50", "Kungsgatan"],
["p4", "p5", "150", "Kungsgatan"]
], SL).
SL= [[Storgatan, 0], [Lillgatan, 0],
[Nygatan, 0], [Kungsgatan ,0]]
accumulate(SL, List).
List=[[Storgatan, 100], [Lillgatan, 200],
[Nygatan, 100], [Kungsgatan ,200]]
This is probably a stupid idea and there is probably a way better way to solve this. I have thought of many different ideas where I either reach a dead end or they are way too complex for such a "simple" task.
I can achieve this easily through "normal" imperative programming but I am new to logical programming and Prolog. I have no idea how to achieve this.
Help?
Thanks!
If you already have a list and you want to group by street name and sum the lengths, you must decide how you do the grouping. One way is to use library(pairs):
streets_lengths(S, L) :-
maplist(street_name_and_length, S, NL),
keysort(NL, NL_sorted),
group_pairs_by_key(NL_sorted, G),
maplist(total_lengths, G, GT),
transpose_pairs(GT, By_length), % sorts!
group_pairs_by_key(By_length, L).
street_name_and_length([_, _, N, L], L_atom-N_number) :-
number_string(N_number, N),
atom_string(L_atom, L).
total_lengths(S-Ls, S-T) :-
sum_list(Ls, T).
You can use it like this:
?- streets_lengths([
["p1", "p2", "100", "Storgatan"],
["p1", "p3", "200", "Lillgatan"],
["p2", "p4", "100", "Nygatan"],
["p3", "p4", "50", "Kungsgatan"],
["p4", "p5", "150", "Kungsgatan"]
], SL).
SL = [100-['Storgatan', 'Nygatan'], 200-['Lillgatan', 'Kungsgatan']].
Since there can be many streets with the same length, the results are returned grouped by length. You can get the "shortest" and "longest" by getting the first and last element of the list, like this:
L = [First|_], last(L, Last)
Since this is homework I won't give you the entire answer but the key part of the code.
As I noted in the comments, the format of the structure matters, e.g. list, terms, atoms, strings, etc.
test(Street_lengths,Shortest) :-
List =
[
street(p1, p2, 100, 'Storgatan'),
street(p1, p3, 200, 'Lillgatan'),
street(p2, p4, 100, 'Nygatan'),
street(p3, p4, 50, 'Kungsgatan'),
street(p4, p5, 150, 'Kungsgatan')
],
street_lengths(List,Street_lengths),
lengths1(Street_lengths,Lengths),
min_list(Lengths,Min),
convlist(value_shortest2(Min),Street_lengths,Shortest).
street_lengths([H|T],Street_lengths) :-
merge_streets(H,T,Street_lengths).
% 2 or more items in list
merge_streets(street(_,_,Length0,Name),[street(_,_,Length1,Name),street(_,_,Length2,Name2)|Streets0],[street(Length,Name)|Streets]) :-
Length is Length0 + Length1,
merge_streets(street(_,_,Length2,Name2),Streets0,Streets).
merge_streets(street(_,_,Length0,Name0),[street(_,_,Length1,Name1)|Streets0],[street(Length0,Name0)|Streets]) :-
Name0 \= Name1,
merge_streets(street(_,_,Length1,Name1),Streets0,Streets).
% 1 item in list
merge_streets(street(_,_,Length0,Name),[street(_,_,Length1,Name)],[street(Length,Name)]) :-
Length is Length0 + Length1.
merge_streets(street(_,_,Length0,Name0),[street(_,_,Length1,Name1)],[street(Length0,Name0)|Streets]) :-
Name0 \= Name1,
merge_streets(street(_,_,Length1,Name1),[],Streets).
% no item in list
merge_streets(street(_,_,Length,Name),[],[street(Length,Name)]).
lengths1(List,Lengths) :-
maplist(value_length1,List,Lengths).
value_length1(street(Length,_),Length).
value_shortest2(Min,street(Min,Name),street(Min,Name)).
Example run:
?- test(Street_lengths,Shortest).
Street_lengths = [street(100, 'Storgatan'), street(200, 'Lillgatan'), street(100, 'Nygatan'), street(200, 'Kungsgatan')],
Shortest = [street(100, 'Storgatan'), street(100, 'Nygatan')] ;
false.
I left the longest for you to do, but should be a cake walk.
To display the information as you noted in the question I would use format/2.
So now you either have to change how you get the data read into the format for this code, or change this code to work with how you structured the data. IMHO I would change the data to work with this structure.
If want to know how efficient your code is you can use time/1
?- time(test(Street_lengths,Shortest)).
% 44 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
Street_lengths = [street(100, 'Storgatan'), street(200, 'Lillgatan'), street(100, 'Nygatan'), street(200, 'Kungsgatan')],
Shortest = [street(100, 'Storgatan'), street(100, 'Nygatan')] ;
% 17 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
false.
Related
Erlang Newbie here . Suppose I have two lists which are like this .
L1= [{'Lady in the Water',2.5},
{'Snakes on a Plane',3.5},
{'Just My Luck',3.0},
{'Superman Returns',3.5},
{'You, Me and Dupree',2.5},
{'The Night Listener',3.0}]
and
L2 = [{'Lady in the Water',3.0},
{'Snakes on a Plane',3.5},
{'Just My Luck',1.5},
{'Superman Returns',5.0},
{'You, Me and Dupree',3.5}]
I want the common ratings in a list of tuple like
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5}]
My code is like this
common_rating(R1,R2)->common_rating(R1,R2,0,0).
common_rating(_X,[],M,N) ->{M,N};
common_rating(X,[Y|Y1],A,B)->
{M,R}=X,
{N,K }= Y,
case M=/=N of
true -> common_rating(X,Y1,A,B);
false -> common_rating(X,[],A+R,B+K)
end.
common_rating_final([],_R2,J) ->J;
common_rating_final([X|X1],R2,J)->
common_rating_final(X1,R2,J++[common_rating(X,R2)]).
To better understand the code
common_rating function expects a tuple of {movie,rating} and finds the same movie and rating from another list(B) and returns {rating,rating_B}
Now common_rating_final recursively goes over a list ,lets say A, and uses common_rating to find {rating_A,rating_B} for all movies that are common in A and B both
but when I run my code
my_module:common_rating_final(L1,L2,[]).
it returns me
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5},{0,0}]
I can filter the {0,0} part but I think my logic is flawed but could not able to write a code which returns only the common ratings without the {0,0} part .
Please assist .
TL;DR
[{X2, Y2} || {X1, X2} <- L1, {Y1, Y2} <- L2, X1 =:= Y1].
Maybe the "cracks" here can find a better (more efficient, etc.) solution, but this one works. Basically it pattern matches ("deconstruct") the Ls and compares the first element of the tuples, returning the second element if the first ones happen to be equal.
The whole stuff/proof:
gorre#uplink:~$ erl
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]
Eshell V8.3 (abort with ^G)
1> L1= [{"Lady in the Water",2.5}, {"Snakes on a Plane",3.5}, {"Just My Luck",3.0}, {"Superman Returns",3.5}, {"You, Me and Dupree",2.5}, {"The Night Listener",3.0}].
[{"Lady in the Water",2.5},
{"Snakes on a Plane",3.5},
{"Just My Luck",3.0},
{"Superman Returns",3.5},
{"You, Me and Dupree",2.5},
{"The Night Listener",3.0}]
2> L2 = [{"Lady in the Water",3.0}, {"Snakes on a Plane",3.5}, {"Just My Luck",1.5}, {"Superman Returns",5.0}, {"You, Me and Dupree",3.5}].
[{"Lady in the Water",3.0},
{"Snakes on a Plane",3.5},
{"Just My Luck",1.5},
{"Superman Returns",5.0},
{"You, Me and Dupree",3.5}]
3> [{X2, Y2} || {X1, X2} <- L1, {Y1, Y2} <- L2, X1 =:= Y1].
[{2.5,3.0},{3.5,3.5},{3.0,1.5},{3.5,5.0},{2.5,3.5}]
4>
Notice that I changed the atoms into strings (it works the same way though).
Let's assume I have something like:
% person(ID, Name, Age)
person(_, paul, Age).
person(_, Name, 20).
...
...and instead of the typical binding I would like to have a helper function get_person_list(ID, Name, Age) that calls person but returns me a list:
?- get_person_list(_, Name, 20).
[frank, jack, jane].
...to get a list for e.g. all persons with age 20. How can I achieve this?
Do not use findall/3 for this. This is the perfect example of how bagof/3 and setof/3 are different from findall/3.
Your example is a bit strange, so here is another database. I removed the first argument because you don't seem to be using it, and added more rows so that there can be more different ages. Note that it makes no sense to have free variables in a table of facts like person, so all rows have values at both positions.
person(abel, 20).
person(bill, 30).
person(clive, 20).
person(diana, 10).
person(evan, 200).
person(fia, 20).
people_age(Age, Ps) :-
bagof(P, person(P, Age), Ps).
With this definition of people_age/2, you can query, for example:
Who are the people aged 20?
?- people_age(20, Ps).
Ps = [abel, clive, fia].
Group people by their age.
?- people_age(Age, Ps).
Age = 10,
Ps = [diana] ;
Age = 20,
Ps = [abel, clive, fia] ;
Age = 30,
Ps = [bill] ;
Age = 200,
Ps = [evan].
Who is at least 30 years old?
?- people_age(Age, Ps), Age >= 30.
Age = 30,
Ps = [bill] ;
Age = 200,
Ps = [evan].
The last one could be done differently, if you don't want to group by age. Here is how:
?- bagof(P, Age^( person(P, Age), Age >= 30 ), Ps).
Ps = [bill, evan].
or maybe
?- bagof(Age-P, Age^( person(P, Age), Age >= 30 ), Ps).
Ps = [30-bill, 200-evan].
... if you don't want to throw away the age completely.
But you should just read up on "collecting all solutions in Prolog" and the intended use of all three: findall/3, bagof/3, setof/3.
You could simply write: findall(X,person(_,X,20),L).
This will return you a list L which is the list you asked...
Example:
person(_, name1, 20).
person(_, name2, 20).
person(_, name3, 20).
person(_, name4, 20).
person(_, name5, 20).
?- findall(X,person(_,X,20),L).
L = [name1, name2, name3, name4, name5].
In your code, you don't provide a parameter for the resulting list.
Just call:
findall(Id, person(Id, _, 20), L).
You can make a separate predicate for this query if you really need it often, of course.
get_person_list(Id, List) :-
findall(Id, person(Id, _, 20), List).
See also bagof/3, as explained in Boris's answer.
Could some one please help me out!
I have a dictionary with key and values.Each key is a cluster label, and the values associated with the keys are the data points in that cluster.Each data point is a list with 60 columns(ie, a time series data with length 60).I want to assemble these time series row wise for supervised classification such that the each time series data point has the key(say 0) as its last value in the row as its class.(eg: 0.1,0.3,0.5, 0)where the last value zero is the class value. Here is part of my real data.
{0: array([[ 28.7812, 34.4632, 31.3381, ..., 33.3759, 25.4652, 25.8717],
[ 24.8923, 25.741 , 27.5532, ..., 34.2484, 32.1005, 26.691 ],
[ 31.3987, 30.6316, 26.3983, ..., 33.9002, 29.5446, 29.343 ],
...,
[ 24.4293, 39.7616, 40.1207, ..., 42.3223, 31.9421, 32.8973],
[ 32.3175, 39.9719, 40.6855, ..., 28.8281, 41.7112, 35.3453],
[ 25.7836, 34.1285, 42.6593, ..., 34.4315, 32.155 , 34.8388]]),
{1: array([[ 35.7709, 34.396 , 35.2249, ..., 32.4859, 30.7772, 24.5854],
[ 24.9706, 33.8315, 46.9423, ..., 24.1889, 11.4137, 13.1961],
[ 35.5351, 41.7067, 39.1705, ..., 37.7721, 37.2248, 32.9494],
...,
[ 28.0747, 41.7835, 42.1198, ..., 38.0344, 46.4582, 44.4323],
[ 33.6696, 38.6754, 39.7419, ..., 34.9395, 36.9095, 39.7494],
[ 30.5729, 41.0741, 44.9793, ..., 24.353 , 19.7201, 12.7513]])}
In simpler terms, I am only interested in having the values for each row without the brackets and then append it to the row with its key as the last number in the row.
I'm not sure I got your input format right...
input = {0: [['0', '0']], 1: [['0', '0']]}
output = []
for key in input.keys():
input[key].append(key)
output.append(input[key])
old_cluster = []
for i in range (0,len(toy_data)):
d_cluster =np.append(toy_data[i], int(labels[i]))
f_cluster= d_cluster.tolist()
old_cluster.append(f_cluster)
data_cluster=np.asarray(old_cluster)
Writes Data to a text file without the bracket each point on a line with
its cluster label as the last point.
with open('mytest.txt','w') as outfile:
for item in data_cluster:
outfile.write("%s\n" % ','.join(map(str,item)))
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 = [].
As a continuation of my previous question, Simon's method to find the list product of a PackedArray is fast, but it does not work with negative values.
This can be "fixed" by Abs with minimal time penalty, but the sign is lost, so I will need to find the product sign separately.
The fastest method that I tried is EvenQ # Total # UnitStep[-lst]
lst = RandomReal[{-2, 2}, 5000000];
Do[
EvenQ#Total#UnitStep[-lst],
{30}
] // Timing
Out[]= {3.062, Null}
Is there a faster way?
This is a little over two times faster than your solution and apart from the nonsense of using Rule### to extract the relevant term, I find it more clear - it simply counts the number elements with each sign.
EvenQ[-1 /. Rule###Tally#Sign[lst]]
To compare timings (and outputs)
In[1]:= lst=RandomReal[{-2,2},5000000];
s=t={};
Do[AppendTo[s,EvenQ#Total#UnitStep[-lst]],{10}];//Timing
Do[AppendTo[t,EvenQ[-1/.Rule###Tally#Sign[lst]]],{10}];//Timing
s==t
Out[3]= {2.11,Null}
Out[4]= {0.96,Null}
Out[5]= True
A bit late-to-the-party post: if you are ultimately interested in speed, Compile with the C compilation target seems to be about twice faster than the fastest solution posted so far (Tally - Sign based):
fn = Compile[{{l, _Real, 1}},
Module[{sumneg = 0},
Do[If[i < 0, sumneg++], {i, l}];
EvenQ[sumneg]], CompilationTarget -> "C",
RuntimeOptions -> "Speed"];
Here are the timings on my machine:
In[85]:= lst = RandomReal[{-2, 2}, 5000000];
s = t = q = {};
Do[AppendTo[s, EvenQ#Total#UnitStep[-lst]], {10}]; // Timing
Do[AppendTo[t, EvenQ[-1 /. Rule ### Tally#Sign[lst]]], {10}]; // Timing
Do[AppendTo[q, fn [lst]], {10}]; // Timing
s == t == q
Out[87]= {0.813, Null}
Out[88]= {0.515, Null}
Out[89]= {0.266, Null}
Out[90]= True