The title may look like it's a dime a dozen, but it's not. The object of this program is to take these classes (needs)
needs([[ece2090,1,m,13,16],
[ece3520,1,tu,11,14],
[ece4420,1,w,13,16]].
and pair them with college teaching assistants that have the credentials to teach the class and are also free during that time (resources; the value with the day, start, and stop for the TA mean he isn't available at this time.)
resources([[joel, [ece2090,ece2010,ece3520,ece4420],[[m,13,16]]],
[sam, [ece2090,ece4420],[]],
[pete, [ece3520],[[w,13,16]]]].
In this version, each TA can only take one class. I have built a program to do this, and a solution is below.
A = [[ece2090, 1, 'NONE'], [ece3520, 1, joel], [ece4420, 1, sam]] .
These are the pairings of TAs to courses. As you can see, one is labelled none. However, if you look you'll see a valid configuration that assigns all tree TAs (Pete to ECE3520, Sam to ECE2090, and Joel to ECE4420). For the purposes of the following question, both of these will be considered solutions.
How do I display all of the solutions? Findall would typically be the way to go, and having an unavoidable fail clause would do the trick too, but here's the kicker: To prolog, needs and resources are both only one instance of a variable instead of three because they are matrices. For this reason, there's nothing for prolog to back track were I to force backtracking with a fail clause or findall
So is there a way to find all solutions? Can I take every possible arrangement of a matrix somehow and toss them all into the program?
I totally agree with lurker's data organization. In addition, I would say that your problem statement makes me think of a combinatorial optimization. In that case, I'd always recommend to formulate it as a CSP using Constraint Programming and to utilize your Prolog's Constraint Logic Programming over Finite Domains library (CLP(FD)).
Constraint Satisfaction Problems
Generally speaking, CP problems are those which consist of:
A solution to a Constraint Satisfaction Problem (CSP) is an assignment of values {x_1 = V_1, x_2 = V_2, ..., x_N = V_N} such that satisfies all constraints in C. That's the gist. If you want to know more about these kinds of problems I suggest you look for a book at your local library, there should be plenty.
I'd recommend you use this formulation because CLP(FD) libraries have solvers which can be used to find a solution to problems formulated in CP. Using CP, you could structure your program in the following parts:
Implementing CSP in Prolog
I've written a short example to show you how this would be done in SWI-Prolog. To begin with, I'll assume you structure your input data in the following way:
Note that I've allowed the availabilities of each TA to be a bit more complex than in your initial specifications. Since you want to find all possible solutions to your problem, I will encode a solution as a list of lists, where each inner list can take a value between 0 and 1 (that's the variables' domain). Each outer list corresponds to each course, whereas the inner lists correspond to the assignments of TA for that particular course.
If we had only 2 TA's (say, Joel and Sam), the solution above would mean that Joel is assigned to the first course while Sam is assigned to the second. What you want to do is to define unbounded variables with the domain
0..1
, apply all necessary constraints, and then automatically solve it (i.e. label).Here,
assign/4
is generating a list of assignments as defined above. However, the values are not bound to neither 0 nor 1. The listASs
would look something like this:In essence, the
assign/4
predicate is simply placing0
for each item TA-course that does not match, a priori, any of the conditions (i.e. an assignment is0
if the TA doesn't have the credentials to teach the course or if he/she is busy at that particular time).If this was your homework I'd suggest you stop reading here and try to provide your own implementation of
assign/4
. I will leave my own in case you are not familiar with CP or want to find a bit of inspiration. I've used the predicateavailable(?TA,+C)
which succeeds when the teaching assistantTA
is available to teach the courseC
and has the necessary credentials to do so. In addition the predicateassign_(?Xs:list, +TAs:list, ?Ms:list)
is a simple predicate which will bind the variables (X
) to 0 when theTA
is not a member of the list of available TA's inMs
.See
sum/3
to understand how constraints are applied. In order to complete the program you'd simply need to provide an implementation to theavailable/2
predicate. Then, the following call would give you one answer:If you want each possible solution, you'd simply use
findall/3
again:I haven't really tested my program, it was only meant to be illustrative, but I hope you find it helpful anyway.
NOTE: Bear in mind that combinatorial problems (and specially this one in which you want all solutions) are computationally complex. I imagine you want to find those to later optimize your timetable. That being the case I'd encourage you to do so within the program itself (i.e.
labeling/2
).This is probably an assignment, so I'll stop short of giving away a complete solution. But I would recommend structuring your information differently, to be more typical of how it's done in Prolog:
Here, rather than having embedded lists in facts, each fact stands on its own. Each distinct functor is like one table in a database that you can query, and the different functors are different tables that are interrelated based upon some argument.
So if you want to know what
joel
is qualified for:If you need a list of all the qualified TAs:
If you want to see what needed classes
joel
is available for and qualified to teach:The assumption above is that "schedule" blocks are all described in the same way,
[day, start, end]
as you show, so they can simply be matched as entire 3-element lists. With a little extra effort, this can be more generalized to check days and time intervals in more detail. But that doesn't appear to be a requirement for you. The above are good building blocks to help solve your problem. It only requires a few lines of code (I used only 12 lines, plus the above facts). :)