PlanForMe, the iOS app I've been developing for the past few weeks, is now available on the app store! The official description is:
PlanForMe is an automated assistant that optimizes and organizes your schedule for you. It makes planning your day quick and easy, whether you have a lot of overlapping events or just want to prioritize your meetings and activities.
- Order your events by priority
- Sort events into "Must do", "Would like to do", and "Don't want to do" categories
- Integrates with your calendars
- Creates your plan for the day, taking into account each event's category and priority
Just tap a button to add the plan to your calendar!
I've wanted to create an app like this ever since the start of last fall semester, when my calendar was double, triple, and quadruple booked with meetings, events, classes, parties, office hours, review sessions, sports practice etc ... I just wanted something that would schedule out my day for me, yet require minimal work on my end. Many undergrads have cluttered schedules, but this problem is definitely not unique to college students! Although I tried apps like Plan, Handle, and many different calendar apps, all of them required work on my part to figure out my optimal schedule for the day.
The languages, tools, and frameworks that I decided to use were
- Firebase Auth and Database for authentication, querying, and storage
- Swift/Xcode as in my other apps
- EventKit for calendar integration
- Assembly for UI design
I decided to use Firebase because I've been working with it all last semester during my UROP. Although I was working with the web API to integrate Firebase storage into a web framework, I found it easy to cross over into using Firebase for iOS app development.
At the heart of the app is a modified interval scheduling algorithm (translating each calendar event as an interval) that I first heard about in an algorithms class I took last fall. Since users can order their events by priority in PlanForMe, the intervals are weighted and a greedy algorithm doesn't work. A greedy algorithm that works for unweighted interval scheduling is picking the interval with the earliest finish time at each iteration, and removing all conflicting intervals before the next iteration. A simple counterexample that shows this greedy algorithm doesn't work for weighted intervals is an event A that goes from 1-5 PM with weight 100, and an event B that goes from 1-3 PM with weight 1. The greedy algorithm would choose event B even though event A is more optimal.
Instead, we must use a O(NlogN) dynamic programming algorithm for weighted interval scheduling. Here's a sketch of the general algorithm:
- Sort intervals by finish times (earlier finish times to later finish times). O(NlogN).
- For each interval X, binary search for the index of the latest interval before X that doesn't conflict with X and store it in an array P. O(NlogN).
- Side note: If such an interval doesn't exist, return -1 or 0 depending on if you 0- or 1-indexed your array
- Now to find the maximum total weight of a set of non-conflicting intervals, we define an array M to store the maximum possible total weight of the first i intervals at M[i].
- Our recursion is M[i] = max(weight of ith interval + M[P[i]], M[i-1]). In other words, if we choose to include the ith interval in our solution, our total weight would be sum of the weight of the ith interval and the optimal solution for the set of intervals that don't conflict with interval i. If we choose to not include the ith interval in our solution, our optimal solution for intervals 1 through i is just the optimal solution for intervals 1 through i-1. Our final maximum total weight for all intervals 1 through N is M[N]. O(N).
- You could stop at this point if you just wanted to know the maximum total weight of non-conflicting intervals, but for PlanForMe, users would like to know which of their calendar events actually make up the optimal solution. In this case, we can just recursively trace back to find the intervals that make up the optimal solution. O(N).
In the future
I'm planning on adding some deep learning capabilities so the app will get even smarter. Specifically, some features and tweaks I decided to push to a later version of PlanForMe were:
- By default, when a user sees their events for the first time, all day events are in the all day category, and all other events are in the "Would like to do" category, sorted by start time. I would like to develop a smarter way to rank tasks automatically to further minimize the amount of work a user has to do to organize their day. For example, PlanForMe could notice that a user usually picks working out at the gym over going to happy hour, or prioritizes events on their Family calendar over their Work calendar, or rarely chooses to go to a certain meeting.
- Currently, all events must already be scheduled in a user's calendars to appear in PlanForMe. It'd be cool to let users also add unscheduled tasks that PlanForMe could schedule in optimally based on duration and location.
- I would also like to work on weighting events more intelligently. Right now, priorities are calculated using a constant scaling factor.
All code mentioned in this post is posted on my Github account.
Please try out PlanForMe and share your feedback!
Please try out PlanForMe and share your feedback!