I am writing a staff scheduler for my office. There are at least two shifts per day (7 days a week) and I want the optimizer to make sure no one staff member works drastically more weekend shifts than another.
I have a simple working program that assigns one Staff to each Shift.
The program structure is as follows:
SchedulingSolution is the #PlanningSolution
SchedulingSolution contains a List<Shift> which is the #PlanningEntityCollectionProperty
Shift is the #PlanningEntity
Shift contains a Staff which is the #PlanningVariable
SchedulingSolution contains a #ValueRangeProvider which returns our staff roster as a List<Staff>.
This working solution schedules all staff equally but does not consider weekends and weekdays. To delineate weekdays from weekends, I have replaced the List<Shift> in SchedulingSolution with a List<Day>. Every Day contains its own List<Shift> representing the shifts that occur on that day. Now when I want to compute the number of weekends a staff member has worked, I can find all Day objects that represent weekends and count only the Shifts contained in those days.
Unfortunately, this places the List<Shift> which is the #PlanningEntityCollectionProperty in a class that is not a #PlanningSolution. The #PlanningEntityCollectionProperty annotation is now ignored and the program fails.
Have I missed an obvious way to restructure my program, or is my only option to keep my original program structure and modify my shift objects to record which day they occur on?
Thanks in advance. I'll try to pass the help forward if I can.
I would restructure your Planning Solution.
Why don't you do:
Keep the List<Shift> in the Planning Solution
Discard the List<Day> in every shift
Add a field day in Shift, possibly even an indicator whether that day is a weekend using an enum.
You can then easily calculate the number of weekend days worked by each staff with Drools as so:
(Absolutely untested!!!)
rule "balancedStaffWeekend"
when
$staff: Staff()
accumulate(
Shift(
staff == $staff
day == Day.WEEKEND);
$count: count()
);
)
then
scoreHolder.addSoftConstraintMatch(kcontext, -Math.pow(count, 2));
end
Penalising the solution by counts raised to the power of two balances the number of weekends.
Related
In my program, there will be students (from multiple year groups/grades) submitting choices for activities running from Monday to Friday.
Each activity may be applicable to one, or multiple year groups. Each student has say 4 choices (1st, 2nd, 3rd and 4th) per day. This is being stored in each student object as int[][] studentCosts which will be studentCosts=new int[5][4].
I have finished my hungarian algorithm but I need to decide how to add all the students' choices to an int[][].
I will be executing the algorithm separately for each day, so I will need to collate all the students' choices for that particular day into an int[][] costsForThatDay.
My problem is with how some year groups may be offered certain activities which are not offered to others, for example, on Monday, Year 7 are offered Windsurfing on Monday, whereas Years 8 and 9 are offered Golf on Monday.
If I were to execute the algorithm by day would it be best to set the 'costs' for unavailable activities to something like Integer.MAX_VALUE to make sure there is absolutely no way it will ever be chosen? E.g. Make Golf 'cost' for year 7 students and Windsurfing 'cost' for year 8 and 9 students Integer.MAX_VALUE
I am trying to write Java code for the following problem.But I am not able to find out a optimized way to solve this .
I have an array list of time and consumption of coffee as follows. I want to calculate the consumption of coffee every hours and if there is no consumption for a particular hour the next hours first entry will be the total consumption for that hour.
For Example :
I have the following array list
Time consumption of coffee
2:15 5 cups
2:30 6 cups
2:45 7 cups
3:05 2 cups
3:45 6 cups
5:05 1 cups
5:30 2 cups
7:15 1 cup
so I want to calculate what is the total consumption for hour 2 which will be in that case 18 cups from 2:00 to 3:00 .again for 3:00 to 4:00 it will be 8 cups. As there is no entry from 4:00 to 5:00 amount of consumption in that case should be amount of coffee consumed at 5:05 which is 1 cup.I want my result till 7 o'clock. As we don't have anything at 6:00 -7 :00 then it will be 1 cup which was value at 7:15.
So I want a final result of total consumption from 2:00 to 7:00 distributed every hour as array list as following object
obj1 = T<2:00,3:00,18>
obj2 = T<3:00,4:00,8>
obj3 = T<4:00,5:00,1>
obj4 = T<5:00,6:00,3>
obj5 = T<6:00,7:00,1>
finalList = <obj1,obj2,obj3,obj4,obj5>
I am not able to get how to chop the list in hourly way and look at the next value as well.
You completely lost me as to the logic of filling an empty hour with first value from the next hour. But I'll give it a shot anyways.
My approach assumes your input data is in chronological order from earlier to later.
Define a CoffeeConsumption class with two members, LocalTime and Integer for your two values.
Create a Map, perhaps a SortedMap such as TreeMap. The key is of type Integer, and represents the hour of the day from 0 to 23. The value is of type Set, perhaps a SortedSet such as TreeSet to store your custom objects defined above.
For each of you custom objects, grab its LocalTime and call getHour. Use that hour number to find the matching key in the Map, retrieve the Set, and add your item.
To get totals, loop the Map, and loop each Set. To save the totals, create a new SortedMap with Integer as key for hour-of-day and Integer as value for the hour’s total number of cups consumed.
Note that there is no need to save explicitly the end-of-hour time as you showed in your Question. You can always calculate that value: call LocalTime::plusHours( 1 ).
To support that move-first-item-to-previous-hour-if-empty feature, follow the logic I just outlined in that hyphenated title. When adding a coffee object to the Map with no existing key yet put there for that hour, first subtract one from the hour and look in the Map for that subtracted number as key. If the subtracted key is not present in the Map, put it, create a fresh empty Set in which to deposit the coffee object that would otherwise have gone to its own hour. Caveat: This feature has a bad smell and suggests something is wrong with your design or the requirement is misunderstood.
Suppose I have a list of projects with start date and end date. I also have a range of weeks, which varies (could be over months, years, etc)
I would like to display a graph showing 4 values per week:
projects started
projects closed
total projects started
total projects closed
I could loop over the range of weekly values, and for each week iterate through my list of projects and calculate values for each of these 4 trends per week. This would have algorithmic complexity O(nm), n is the length of list of weeks, and m is the length of projects list. That's not so great.
Is there a more efficient approach, and if so, what would it be?
If it's pertinent, I'm coding in Java
While it is true what user yurib has said there is a more efficient solution. Keep two arrays in memory projects_started and projects_ended, both with size 52. Loop through your list of projects and for each project increment corresponding value in both lists. Something like:
projects_started[projects[i].start_week]++;
projects_ended[projects[i].end_week]++;
After the loop you have all the data you need to make a graph. Complexity is O(m).
EDIT: okay, so maximum number of weeks can vary apparently, but if it's smaller than some ludicrous number (more than say a million) then this algorithm still works. Just replace 52 with n. Time complexity is O(m), space complexity is O(n).
EDIT: in order to determine the value of total projects started and ended you have to iterate through the two arrays that you now have and just add up the values. You could do this while populating the graph:
for (int i = 0; i < n)
{
total_started_in_this_week += projects_started[i];
total_ended_in_this_week += projects_ended[i];
// add new item to the graph
}
I'm not sure what the difference between "project" and "total" is, but here's a simple O(n log n) way to calculate the number of projects started and closed in each week:
For each project, add its start and end points to a list.
Sort the list in increasing order.
Walk through the list, pulling out time points until you hit a time point that occurs in a later week. At this point, "projects started" is the total number of start points you have hit, and "projects ended" is the total number of end points you have hit: report these counters, and reset them both to zero. Then continue on to process the next week.
Incidentally, if there are some weeks without any projects that start or end, this procedure will skip them out. If you want to report these weeks as "0, 0" totals, then whenever you output a week that has some nonzero total, make sure you first output as many "0, 0" weeks as it takes to fill in the gap since the last nonzero-total week. (This is easy to do just by setting a lastNonzeroWeek variable each time you output a nonzero-total week.)
First of all, I guess that actually performance won't be an issue; this looks like a case of "premature optimization". You should first do it, then do it right, then do it fast.
I suggest you use maps, which will make your code more readable and outsources implementation details (like performance).
Create a HashMap from int (representing the week number) to Set<Project>, then iterate over your projects and for each one, put it into the map at the right place. After that, iterate over the map's key set (= all non-empty weeks) and do your processing for each one.
I'm new. I'm writing an app for a laser tag place where we've got kids of many ages coming to shoot beams at each other. We're making a highscore screen that'll display the best scores of the day, of the week, and of the month. The idea is that people will feel proud being on the list, and there'll also be prizes once a month.
I'm getting stuck at the whole filtering by date thing.
I basically modified the classic guestbook example to the point where I can add scores and customer info, and sort them by score.
Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
String fornavn = req.getParameter("fornavn");
Integer score = Integer.parseInt(req.getParameter("score"));
String email = req.getParameter("email");
String tlf = req.getParameter("tlf");
Date date = new Date();
Entity highscore = new Entity("Greeting", guestbookKey);
highscore.setProperty("date", date);
highscore.setProperty("fornavn", fornavn);
highscore.setProperty("score", score);
highscore.setProperty("email", email);
highscore.setProperty("tlf", tlf);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(highscore);
And in the jsp there's a query that grabs the overall top 5.
Query query = new Query("Highscore", highscoreKey).addSort("score", Query.SortDirection.DESCENDING);
List<Entity> greetings = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
And there's a form that sends the user input to the .java. Any tips as far as how I should set up the dates? Saving week # and month # and querying based on that? Seems cumbersome.
From what I can tell, your "HighScore" kind is actually a "Score" kind that keeps track of all scores.
Instead of querying for the high score for the week/month, you're probably better off having a single HighScore entity (that's separate from normal "Score" entities) that you update whenever you enter a score. Every time a new score is entered, check if the high score should be updated.
You never need a fancy query, you just need to fetch the high score entity.
Or you might want a separate high score entity for each month/week etc so you can keep track of the history. In this case you may want to encode week or month into the entity key, so you can get the current week/month's HighScore easily.
There are 2 possible approaches for a requirement like yours where you want to show highscores for a day, week, month, etc:
1, First option is to use your current model where you are storing date and score. Since app engine allows inequality filter only on 1 property, you need to apply an inequality filter on date and then find the n highest number of scores. But since the result will be sorted first for the property with inequality filter and then for any additional property, you cannot do a fetch for only the first n entries to find the top n because the top scores need not be in continuous order. See this post to understand this better. So you will have to fetch all the scores for the date range and then do further sorting of the query result at your client to find the top n. This approach is ok if the total number of scores for a week or a month will not be too high compared to the value of n. If not, this is not a scalable option.
2, Second approach is to redesign your model such that sorting happens on scores so that for getting top n scores for a particular period, you need to fetch only the first n entries. This means the approach is suitable even if number of scores are very large. This then requires converting your date to be suitable for equality filtering like for each entry storing a month number, a week number and calendar year. Then for example if you want to find the top n scores in the 3rd month, then you can query for month=3, sort by scores descending and fetch the first n matching entries. Similarly you can query for a particular week using a week number.
This is very similar to another high-score SO question. I have copied/pasted my answer to it below. Approaching this solution using a database query may cause you to join the ranks of folks who complain about GAE. You will be using a custom index. Your query will likely average 10x miliseconds slower than needed per request. You will need to index thousands, perhaps millions of records. This costs you money -- perhaps lots of it both re: data storage (indices) and instances due to your high latency for what will likely be a highly-called handler function. Think different please. My copy/paste is not as specific to your setup, but it can be easily extended easily. I hope that it might prompt you to think about lower resource, lower cost alternative. As always...HTH. -stevep
Previous high score answer:
You may want to consider an alternate approach. This is a lot of index overhead which will cause your costs to be higher, the response time for the handler executing this function to operate an order of magnitude slower and you will have moments where the eventual consistency of index updates will affect maintenance of this data. If you have a busy site, you will surely not be happy with the latency and costs associated with this approach.
There are a number of alternate approaches. Your expected site transactions per second would affect which you choose. Here is a very simple alternative. Create an ndb entity with a TextProperty. Serialize the top scores entries using a string such as score_userid. Store them in the text field by joining them with a unique character. When a new score comes in, use get_by_id to retrieve this record (ndb automatically handles memcaching for you). Split it into an array. Split the last element of the array, and check against the new score. If it is less than the score, drop it, and append the new score_userid string to the array. Sort the array, join it, and put() the new TextProperty. If you want you could set up an end of the day cron to scan your scores for the day to check to see if your process was affected by the very small chance that two scores arrived at nearly the same time causing one to overwrite the other. HTH. -stevep
Previous SO high score answer link:
GAE datastore query with filter and sort using objectify
I am trying to seek a solution for timetable generation using Genetic Algorithms(GA).
In my scenario i view a timetable of 6 days. Monday to Saturday.
Each day is divided into number of lectures/Time slots.(maximum no. of lectures are 6 in a day/Each time slot if 1 hr so that means 6 hours for a day)
I have tried to represent a Class consisting of Teacher,Student Group(set), and a lecture.
I maintain a pool of possible teachers,possible subjects and possible student groups.
And i randomly assign them to these Class.
so a Class is collection of all these references.
so for each time slot we have the Class object representation in it.
similarly a day is made up of number of lectures Class object representation.
and so on with the week making up of 6 days.
A set of possible constraints that i have is:
1.A teacher can take only one lecture in one time slot
2.A teacher can take a set of subjects(finite)
3.A teacher can be unavailable on a certain day
4.A teacher can be unavailable on a certain timeslot
And other constraints as it may be included lately.
Can anyone give me a idea about how to represent these constraints or handle these constraints? and how to calculate the fitness scores depending on constraints?
EDIT : The implementation is here https://github.com/shridattz/dynamicTimeTable
UPDATE:
The code can be found here
github.com/shridattz/dynamicTimeTable
In my TimeTable Generation I have used A timetable object. This object consists of ClassRoom objects and the timetable schedule for each them also a fittness score for the timetable.
Fittness score corresponds to the number of clashes the timetable has with respect to the other schedules for various classes.
ClassRoom object consists of week objects.Week objects consist of Days. and Days consists of Timeslots. TimeSlot has a lecture in which a subject,student group attending the lecture and professor teaching the subject is associated
This way I have represented the timetable as a chromosome.
And further on talking about the constraints, I have used composite design pattern, which make it well extendable to add or remove as many constraints.
in each constraint class the condition as specified in my question is checked between two timetable objects.
If condition is satisfied i.e there is a clash is present then the score is incremented by one.
This way the timetable with the least Score is the Best we can get.
For this problem ther is no efficint solution. I think you got that too because you use genetic algorithms. I wrote some month ago a framework for genetic algorithm myself.
I think you missed: every class has a list of lessons per week and only one lesson can happen at a time. Now you can combine randomly teachers and classes for the timeslots.
In the fitnes function I'd give a huge plus if a class has all lessons to do a week. A big minus would be if teachers haven't simmilar load (teacher a has two lessons a week and teacher b 12 for example). This you might relativate if a teacher has to work just 20 hours a week (use %).
All in all it is not that trivial and you might look for an experienced co-worker or mentor to help you with this topic.
If you want more specific advises, please specify your question.