Prolog Permutations scheduling - recursion

I have the following file with the predicate attends which symbolizes that every student attends a certain course
(the first argument : Student_ID, the second argument : Course_ID).
attends(476, c216).
attends(478, c216).
attends(484, c216).
attends(487, c216).
attends(491, c216).
What I want to do is create a predicate-function which creates an examination schedule consisting of 3 lists (A,B,C) with courses.
Each list symbolizes a week. Then for instance to find the optimal schedule in order it suits most students, it prints out all the different permutations of courses in pairs of 3-3-2:
The list A is week one with courses [c204,c209,c210] in the first case bellow.
List B is week 2 etc...
?- schedule(A,B,C).
A = [c204,c209,c210],
B = [c212,c214,c216],
C = [c217,c218];
A = [c204,c209,c210],
B = [c212,c214,c216],
C = [c218,c217];
Problem 1:
So how can I take the attends/2 predicates and convert only the second argument to a List, in a manner that the list will contain all the courses that have been declared.
For example: L = [c212,c213...].
Problem 2:
The permutations will be done with a custom function called k_permutation/3:
delete(E,L,NL):-
append(L1,[E|L2],L),
append(L1,L2,NL).
k_permutation(0,_,[]).
k_permutation(K,L1,[X|T2]) :-
K > 0,
K1 is K - 1,
delete(X,L1,L2),
k_permutation(K1,L2,T2).
But for some reason this custom function (k_permutation/3) runs for infinite time. Is there something wrong with the functions recursion?
How should the function be used?

Well as for problem 1 the easy way would be:
collect_courses(L1):- findall(Course, attends(_,Course), L), sort(L,L1).
L will have all courses that appear in attends/2, so it will have duplicates, that's the reason we're using sort/2 which removes duplicates.
As for problem 2, first of all Swi-Prolog already has a definition of delete/3 predicate so I suggest that you rename it. Apart from that the k_permutations/2 works fine:
?- k_permutation(2,[1,2,3],L).
L = [1, 2] ;
L = [1, 3] ;
L = [2, 1] ;
L = [2, 3] ;
L = [3, 1] ;
L = [3, 2] ;
false.

Related

Understand Function capturing through map and reduce

I 'am beginner in Elixir language , so In the blow example
iex> Enum.reduce([1, 2, 3], 0, &+/2)
6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
In the reduce method I understand that we capture the second arg and we add to it the list values until we reach the end of the List .
but in the map method I can't understand how the capturing works?
reference
http://elixir-lang.org/getting-started/recursion.html
map/2 and reduce/2 are two different functions.
map/2 takes some values and a function that takes a single value and applies that function to each element in the collection, effectively transforming it into a list.
reduce/2 takes some values and a function that takes 2 arguments. The first argument of that function is the element in your collection, while the second is an accumulator. So the function reduces your collection down to a single value.
Using the syntax &+/2, this does not capture the second argument. It calls the + function on the two arguments. The /2 is to denote that it has an arity of 2 (it takes 2 arguments). Take the following code as an example.
iex(1)> fun = &+/2
&:erlang.+/2
iex(2)> fun.(1,2)
3
Here, we set the + function to the variable fun. We can then apply that function to our arguments in order to get a value.
The other syntax &(&1 * 2) creates an anonymous function that takes our one and only argument (represented by &1) and multiplies it by 2. The initial & just means that it is an anonymous function.
iex(3)> fun2 = &(&1 * 2)
#Function<6.118419387/1 in :erl_eval.expr/5>
iex(4)> fun2.(5)
10
They are similar concepts, but slightly different.
Basically:
map returns you new list as a result of applying function on each element of the list
reduce returns you result of the computation of applied function over the list - you reduced the whole collection into (most likely) one result eg. integer
In your example:
iex> Enum.reduce([1, 2, 3], 0, &+/2)
# it equals:
0 + 1 # first step, 1 is out of the list now
1 + 2 # second step, 2 is out of the list now
3 + 3 # last step, 3 is out of the list now, return 6
iex> Enum.map([1, 2, 3], &(&1 * 2))
[2, 4, 6]
# apply for each element function fn(x) -> 2 * x end, but with syntactic sugar
There are three different ways to express an anonymous function, when passing it as an argument:
Enum.reduce([1, 2, 3], 0, fn p1, p2 -> p1 + p2 end)
or, using a shorthand and enumerated params:
Enum.reduce([1, 2, 3], 0, &(&1 + &2))
or, explicitly naming the function of the respective arity (2 for reduce, because reduce expects a function of arity 2):
Enum.reduce([1, 2, 3], 0, &+/2)
The latter, while looking cumbersome, is just a common way to write a function name with it’s arity. Kernel.+/2 is a function name here. If you were using your own function as the reducer:
defmodule My, do: def plus(p1, p2), do: p1 + p2
Enum.reduce([1, 2, 3], 0, &My.plus/2)
All three ways described above are 100% equivalent.
JIC: For the mapper those three ways would be:
Enum.map([1, 2, 3], fn p -> p * 2 end)
Enum.map([1, 2, 3], &(&1 * 2))
—
The third notation is not available here, since there is no such a function, that takes a number and returns it’s doubled value. But one might declare her own:
defmodule Arith, do: def dbl(p1), do: p1 * 2
Enum.map([1, 2, 3], &Arith.dbl/1) # map expects arity 1
#⇒ [2, 4, 6]

List comprehensions and tuples in Julia

I am trying to do in Julia what this Python code does. (Find all pairs from the two lists whose combined value is above 7.)
#Python
def sum_is_large(a, b):
return a + b > 7
l1 = [1,2,3]
l2 = [4,5,6]
l3 = [(a,b) for a in l1 for b in l2 if sum_is_large(a, b)]
print(l3)
There is no if for list comprehensions in Julia. And if I use filter(), I'm not sure if I can pass two arguments. So my best suggestion is this:
#Julia
function sum_is_large(pair)
a, b = pair
return a + b > 7
end
l1 = [1,2,3]
l2 = [4,5,6]
l3 = filter(sum_is_large, [(i,j) for i in l1, j in l2])
print(l3)
I don't find this very appealing. So my question is, is there a better way in Julia?
Using the very popular package Iterators.jl, in Julia:
using Iterators # install using Pkg.add("Iterators")
filter(x->sum(x)>7,product(l1,l2))
is an iterator producing the pairs. So to get the same printout as the OP:
l3iter = filter(x->sum(x)>7,product(l1,l2))
for p in l3iter println(p); end
The iterator approach is potentially much more memory efficient. Ofcourse, one could just l3 = collect(l3iter) to get the pair vector.
#user2317519, just curious, is there an equivalent iterator form for python?
Guards (if) are now available in Julia v0.5 (currently in the release-candidate stage):
julia> v1 = [1, 2, 3];
julia> v2 = [4, 5, 6];
julia> v3 = [(a, b) for a in v1, b in v2 if a+b > 7]
3-element Array{Tuple{Int64,Int64},1}:
(3,5)
(2,6)
(3,6)
Note that generators are also now available:
julia> g = ( (a, b) for a in v1, b in v2 if a+b > 7 )
Base.Generator{Filter{##18#20,Base.Prod2{Array{Int64,1},Array{Int64,1}}},##17#19}(#17,Filter{##18#20,Base.Prod2{Array{Int64,1},Array{Int64,1}}}(#18,Base.Prod2{Array{Int64,1},Array{Int64,1}}([1,2,3],[4,5,6])))
Another option similar to the one of #DanGetz using also Iterators.jl:
function expensive_fun(a, b)
return (a + b)
end
Then, if the condition is also complicated, it can be defined as a function:
condition(x) = x > 7
And last, filter the results:
>>> using Iterators
>>> result = filter(condition, imap(expensive_fun, l1, l2))
result is an iterable that is only computed when needed (inexpensive) and can be collected collect(result) if required.
The one-line if the filter condition is simple enough would be:
>>> result = filter(x->(x > 7), imap(expensive_fun, l1, l2))
Note: imap works natively for arbitrary number of parameters.
Perhaps something like this:
julia> filter(pair -> pair[1] + pair[2] > 7, [(i, j) for i in l1, j in l2])
3-element Array{Tuple{Any,Any},1}:
(3,5)
(2,6)
(3,6)
although I'd agree it doesn't look like it ought to be the best way...
I'm surprised nobody mentions the ternary operator to implement the conditional:
julia> l3 = [sum_is_large((i,j)) ? (i,j) : nothing for i in l1, j in l2]
3x3 Array{Tuple,2}:
nothing nothing nothing
nothing nothing (2,6)
nothing (3,5) (3,6)
or even just a normal if block within a compound statement, i.e.
[ (if sum_is_large((x,y)); (x,y); end) for x in l1, y in l2 ]
which gives the same result.
I feel this result makes a lot more sense than filter(), because in julia the a in A, b in B construct is interpreted dimensionally, and therefore the output is in fact an "array comprehension" with appropriate dimensionality, which clearly in many cases would be advantageous and presumably the desired behaviour (whether we include a conditional or not).
Whereas filter will always return a vector. Obviously, if you really want a vector result you can always collect the result; or for a conditional list comprehension like the one here, you can simply remove nothing elements from the array by doing l3 = l3[l3 .!= nothing].
Presumably this is still clearer and no less efficient than the filter() approach.
You can use the #vcomp (vector comprehension) macro in VectorizedRoutines.jl to do Python-like comprehensions:
using VectorizedRoutines
Python.#vcomp Int[i^2 for i in 1:10] when i % 2 == 0 # Int[4, 16, 36, 64, 100]

Prolog: ID number mapping to a list

I have a variable X that may contain multiple values: X = 1; X = 4; X = 7...
These values map to a list that contain x,y,z, or w. Each one of these value/list pairs are split into multiple facts, so I could have:
map(2,[x,y]).
map(3,[x]).
map(9,[y,w]).
I'm trying to write a program that, given X, I can look up these lists and count how many occurences of x,y,z, or w there are.
This is my attempt:
count(A,B,C,D,X) :- A = 0, B = 0, C = 0, D = 0,
check_list(X,x,A),
check_list(X,y,B),
check_list(X,z.C),
check_list(X,w,D).
check_list(X,Element,Counter) :-
map(X, List),
member(List, Element),
S is Counter + 1,
Counter = S.
The idea behind my program is I call check_list to check if there is a member that contains x,y,z,w for every possible value of X. If there is that member, I will increment the counter. I then want the values of A,B,C,D to have A = number of occurrences of x, B = number of occurrences of y, etc etc.
You are using Prolog variables wrong. Variables cannot change their values once they are instantiated unless Prolog backtracks to a choice-point previous to the instantiation. For example, in the rule for count/5 you unify A with zero and then you expect that satisfying check_list(X,x,A) will bind A to the number of occurrences of x, but A is not a free variable at that point.
So, you have to remove A = 0, ..., D = 0 from the first rule.
Next, you need a predicate that can be used to find the number of occurrences of an element in a list. You can use findall/3 for that:
occurrences(X, List, N):- findall(_, member(X, List), O), length(O, N).
Or you can write it yourself:
occurrences(_, [], 0).
occurrences(X, [X|Tail], N):-!, occurrences(X, Tail, N1), N is N1 + 1.
occurrences(X, [_|Tail], N):-occurrences(X, Tail, N).

Prolog Recursion breakdown

Hi can someone breakdown this recursive code so i can fully understand the output it is giving. Im really confused as to how its working:
listcomb([],[]).
listcomb([X|Y], [X|Z]) :-
listcomb(Y,Z).
listcomb([_|Y],Z) :-
listcomb(Y,Z).
?- listcomb([1,2,3], X).
X = [1, 2, 3] ;
X = [1, 2] ;
X = [1, 3] ;
X = [1] ;
X = [2, 3] ;
X = [2] ;
X = [3] ;
X = [].
thankyou
It unifies the second argument with all possible combinations of elements from the first argument in the following way:
If the list is empty, you're done (first clause).
One possible combination is combine the head of the list with all possible combinations of the tail of the list (second clause)
Another possible combination is to discard the head of the list and just return all possible combinations of the tail of the list (third clause).
When run, the predicate will exhaust the second clause, than backtrace to the third clause, and so on, until exhausting all options and stopping with the first clause.

How to make recursive nested loops which use loop variables inside?

I need to make a nested loop with an arbitrary depth. Recursive loops seem the right way, but I don't know how to use the loop variables in side the loop. For example, once I specify the depth to 3, it should work like
count = 1
for i=1, Nmax-2
for j=i+1, Nmax-1
for k=j+1,Nmax
function(i,j,k,0,0,0,0....) // a function having Nmax arguments
count += 1
end
end
end
I want to make a subroutine which takes the depth of the loops as an argument.
UPDATE:
I implemented the scheme proposed by Zoltan. I wrote it in python for simplicity.
count = 0;
def f(CurrentDepth, ArgSoFar, MaxDepth, Nmax):
global count;
if CurrentDepth > MaxDepth:
count += 1;
print count, ArgSoFar;
else:
if CurrentDepth == 1:
for i in range(1, Nmax + 2 - MaxDepth):
NewArgs = ArgSoFar;
NewArgs[1-1] = i;
f(2, NewArgs, MaxDepth, Nmax);
else:
for i in range(ArgSoFar[CurrentDepth-1-1] + 1, Nmax + CurrentDepth - MaxDepth +1):
NewArgs = ArgSoFar;
NewArgs[CurrentDepth-1] = i;
f(CurrentDepth + 1, NewArgs, MaxDepth, Nmax);
f(1,[0,0,0,0,0],3,5)
and the results are
1 [1, 2, 3, 0, 0]
2 [1, 2, 4, 0, 0]
3 [1, 2, 5, 0, 0]
4 [1, 3, 4, 0, 0]
5 [1, 3, 5, 0, 0]
6 [1, 4, 5, 0, 0]
7 [2, 3, 4, 0, 0]
8 [2, 3, 5, 0, 0]
9 [2, 4, 5, 0, 0]
10 [3, 4, 5, 0, 0]
There may be a better way to do this, but so far this one works fine. It seems easy to do this in fortran. Thank you so much for your help!!!
Here's one way you could do what you want. This is pseudo-code, I haven't written enough to compile and test it but you should get the picture.
Define a function, let's call it fun1 which takes inter alia an integer array argument, perhaps like this
<type> function fun1(indices, other_arguments)
integer, dimension(:), intent(in) :: indices
...
which you might call like this
fun1([4,5,6],...)
and the interpretation of this is that the function is to use a loop-nest 3 levels deep like this:
do ix = 1,4
do jx = 1,5
do kx = 1,6
...
Of course, you can't write a loop nest whose depth is determined at run-time (not in Fortran anyway) so you would flatten this into a single loop along the lines of
do ix = 1, product(indices)
If you need the values of the individual indices inside the loop you'll need to unflatten the linearised index. Note that all you are doing is writing the code to transform array indices from N-D into 1-D and vice versa; this is what the compiler does for you when you can specify the rank of an array at compile time. If the inner loops aren't to run over the whole range of the indices you'll have to do something more complicated, careful coding required but not difficult.
Depending on what you are actually trying to do this may or may not be either a good or even satisfactory approach. If you are trying to write a function to compute a value at each element in an array whose rank is not known when you write the function then the preceding suggestion is dead flat wrong, in this case you would want to write an elemental function. Update your question if you want further information.
you can define your function to have a List argument, which is initially empty
void f(int num,List argumentsSoFar){
// call f() for num+1..Nmax
for(i = num+1 ; i < Nmax ; i++){
List newArgs=argumentsSoFar.clone();
newArgs.add(i);
f(i,newArgs);
}
if (num+1==Nmax){
// do the work with your argument list...i think you wanted to arrive here ;)
}
}
caveat: the stack should be able to handle Nmax depth function calls
Yet another way to achieve what you desire is based on the answer by High Performance Mark, but can be made more general:
subroutine nestedLoop(indicesIn)
! Input indices, of arbitrary rank
integer,dimension(:),intent(in) :: indicesIn
! Internal indices, here set to length 5 for brevity, but set as many as you'd like
integer,dimension(5) :: indices = 0
integer :: i1,i2,i3,i4,i5
indices(1:size(indicesIn)) = indicesIn
do i1 = 0,indices(1)
do i2 = 0,indices(2)
do i3 = 0,indices(3)
do i4 = 0,indices(4)
do i5 = 0,indices(5)
! Do calculations here:
! myFunc(i1,i2,i3,i4,i5)
enddo
enddo
enddo
enddo
enddo
endsubroutine nestedLoop
You now have nested loops explicitly coded, but these are 1-trip loops unless otherwise desired. Note that if you intend to construct arrays of rank that depends on the nested loop depth, you can go up to rank of 7, or 15 if you have a compiler that supports it (Fortran 2008). You can now try:
call nestedLoop([1])
call nestedLoop([2,3])
call nestedLoop([1,2,3,2,1])
You can modify this routine to your liking and desired applicability, add exception handling etc.
From an OOP approach, each loop could be represented by a "Loop" object - this object would have the ability to be constructed while containing another instance of itself. You could then theoretically nest these as deep as you need to.
Loop1 would execute Loop2 would execute Loop3.. and onwards.

Resources