Optimizing Your Schedule (or: Treating Your Week Like a Solvable Problem)
Everyone wants to optimize their schedule. Or, at least, I really do, because I am privileged enough to have some time to spare, but not so much that I can easily achieve all that I want to. But before we optimize our schedule, we need to decide what are we optimizing it for? We download the apps (no shade, I love them), we colour-code the calendar (or colour in your GitHub activity), we read the book (atomic habits, the power of habit), and we never once stop to write down what we are actually trying to achieve. "Fit in more stuff" isn't realistic nor really the goal.
I spent a good chunk of my academic life on optimization, the mathematical kind, where “optimize” moves away from the generic English meaning and turns into a thing you can define precisely and then solve. And the longer I worked on it, the more I was tempted to apply my nerdy skills to my own schedule. Not that it's necessary, whatsoever or in anyway, but because it's a curiosity, it's fun, and it might help me reformulate and reconsider my priorities. You cannot optimize anything until you have said, out loud, what you want more of, what you refuse to give up, and how much each thing is actually worth to you.
I have made a nifty little switch below. If you are a nerdy type like me, or you are curious to see what ridiculousness I have conjured up, flip the switch on. If you'd rather just read about optimizing your own life schedule from a more philosophical and careful-consideration perspective, keep it off.
# Congratulations. You have opted into nerd mode.
assert len(your_excuses) == 0 # required precondition
What follows works in three steps. First, a clear statement of what you actually want from your time. Second, a reckoning with the limits your week genuinely contains. Third, a practical exercise that makes both visible on one page.
Quick jargon guide (expand)
The optimization terms used in this piece, briefly:
- Objective function: the quantity the solver maximizes. Here, total weighted hours across the week.
- Decision variable: what the solver gets to set. Here, hours allocated to each activity.
- Constraint: a rule the solution must satisfy. The week summing to exactly 168 hours is one.
- Bound: a floor or ceiling on a variable — the minimum or maximum hours an activity can receive.
- Integer programming (IP): optimization where variables must be whole numbers, not fractions.
- Feasible solution: any allocation that satisfies all constraints. Many exist; the solver finds the one with the best objective value.
- Degeneracy: when two or more feasible solutions achieve the same objective value and the solver is indifferent between them.
- PuLP: a Python library for writing and solving linear and integer programming models.
What are you actually trying to maximize?
What do you actually want?
Start with the goal, so we know what we are trying to achieve. In optimization this is called the objective function: the single quantity you are trying to make as large (or as small) as possible. If you say your goal is “health, wealth, family, career, and also learning the cello,” you have not stated an objective, you have stated a wish list, and a wish list cannot be optimized because the moment two items conflict (and they always conflict) you have no rule for deciding between them. The goal might be something like total satisfaction, or meaning, or the accumulated weight of time spent on things you will not regret.
Start with what you actually want from your life, not the official answer you give when someone asks, but the real one. Most scheduling advice skips the step that matters: you can only move purposefully in one direction at a time. If your goal is health, family, career, learning, and also the cello, you have not stated a goal. You have stated a wish list. And a wish list has no tiebreaker: the moment two things compete, and they always compete, you have no rule for deciding which one wins. Picking one direction does not mean abandoning the others. It means knowing, in advance, which one wins when they conflict.
In practice, your one goal might be something like: spend my time in a way I will not regret. Or: make sure the people I love know they come first. Or: do work that matters, sleep enough to do it well, and leave something for myself.
Formally, we have a set of activities you could spend time on, indexed by \( i \). For the model running through this post, that set is:
The set \(A\) simply lists the nine activities the week can be spent on. Everything else is built on top of this list.
For each \( i \in A \) (activity in the set of activities) we choose \( x_i \) (the number of hours per week allocated to that activity). These are the decision variables, the dials we get to fiddle with to try different solutions to the problem. The objective is a function we want to maximize, and in the simplest useful form it is linear (the output changes in direct, exact proportion to the input). Call the thing we are maximizing “value,” whatever that means for you. Each hour of activity \( i \) is worth \( w_i \) units of value, and total value is the sum of all of these:
Read it left to right: maximize \(Z\), the total value, which is the sum (that is what \(\sum\) means) over every activity \(i\) of its hours \(x_i\) multiplied by how much you value it, \(w_i\).
\( Z \) is the one number. Choosing the weights \( w_i \) is its own battle, and it is exactly the question (what is each thing worth to you?) that we will need to answer later. We now know the end of the story but not the beginning: at some point we are going to add up all of the values into a single number, \( Z \), and it will represent the quality of our solution. Now we can go deeper into how to get to the point of adding the values up.
Defining our limits
Next come the limits. A goal with no limits is a fantasy: if there were no restrictions you would simply do infinite amounts of every good thing, and the planning problem would not exist. The reason scheduling is hard, and the reason it is interesting, is that you are working inside a box you did not get to choose the size of.
The most ruthless restriction is: there are 168 hours in a week. One hundred and sixty-eight, allocated whether you decide on purpose or not. Every hour you spend on one thing is an hour you did not spend on another.
“All we have to decide is what to do with the time that is given us.” — Gandalf
There are two flavours of limit: Hard constraints are non-negotiable: you must sleep (maybe not exactly 8 hours a night but maybe 6 minimum no matter what); school starts at 0800; your contract wants its forty hours. Soft constraints are the ones you have a bit more leeway with: working out, gardening, walking the dog, even laundry etc. I think a lot of my personal anxiety comes from wanting to treat my soft constraints like hard constraints (I wanna hit the gym 4-5x a week, realistically I'm lucky to do 1-2x). So, write these out - what are non-negotiables, which are negotiables?
There are two kinds of limit. Some limits are something we can't reschedule or choose not to include: you will sleep; your contract wants its forty hours; the school bus arrives at half eight regardless of your plans. These cannot be moved. Writing things down forces you to ask, one by one: is this actually fixed, or just a habit I have mistaken for a law?
Translating these, constraints are inequalities (or equalities) the solution has to respect. The week is an equality: every hour goes somewhere, even if “somewhere” is doing nothing:
The hours you spend across all activities must add up to exactly 168, the number of hours in a week.
Each activity gets a lower and upper bound. A lower bound is a floor you refuse to drop below (a minimum of family time, a minimum of sleep); an upper bound is a ceiling beyond which more hours are impossible or pointless:
For every activity (\(\forall\) means “for all”), its hours \(x_i\) must sit between a floor \(\ell_i\) and a ceiling \(u_i\): never less than the minimum, never more than the maximum.
For our nine activities:
| Activity \(i\) | \(\ell_i\) | \(u_i\) |
|---|---|---|
| family | 14 | 28 |
| sleep | 49 | 56 |
| deep work | 0 | 15 |
| exercise | 0 | 10 |
| learning | 0 | 10 |
| leisure | 0 | 20 |
| paid work | 40 | 40 |
| chores | 7 | 14 |
| doomscrolling | 0 | 168 |
And because hours are lumpy (you do not schedule 3.7 hours of exercise, you schedule 3 or 4) we require the variables to be integers (also just to make this easier to think about). That means this isn't a linear program, it's an integer program, and it is also what lets us model genuine yes/no decisions, which we will need in a moment:
Every activity’s hours must be a whole number that is zero or more. \(\mathbb{Z}_{\ge 0}\) is shorthand for the non-negative integers (0, 1, 2, 3, and so on).
For the example running through this post, the real, unmovable limits are: sleep (the body insists on roughly seven hours a night, eight if you can manage it); paid work (forty hours, fixed by contract); chores (about an hour a day); and a minimum of family time.
Everything else is open. Exercise, learning, leisure, deep work: no fixed floor, no fixed ceiling. The question, for each of those, is how much of the remaining hours you choose to give them. That choice is where your real priorities become legible.
Not everything counts the same
We treat our to-do list as if every item carried equal weight, so we do the easy, low-value things first because they are easy, and the hard, high-value things drift to “later,” which is a place that does not exist. An hour with my family and an hour clearing my inbox are both, technically, an hour. They are not remotely the same hour.
The fix is to attach a weight to each thing: a number standing for how much you actually care about it, not how urgent it feels or how loudly it pings (I'm talking to you Google Tasks). Your husband says "I miss you, I'd like to spend more time with you this week", and suddenly you modify your weightings. My weights are not your weights. The point is not to get them “right” in some universal sense; the point is to make them explicit, because the alternative is not having no weights, it is having invisible ones you never chose and cannot examine. Everyone is already running a weighted optimization. Most people have just never read out their own coefficients, mostly because not everyone is a nerd like we are.
The fix is to score each thing: a number standing for how much you actually care about it, not how urgent it feels or how loudly it pings (I'm talking to you, Google Tasks). My scores are not your scores. And they're likely to change! Your husband says "I miss you, I'd like to spend more time with you this week", and suddenly you modify your scores. The point is not to get them “right” in some universal sense; the point is to make them explicit, because the alternative is not having no priorities, it is having invisible ones you never chose and cannot examine. Everyone is already treating some things as more important than others in how they spend their time. Most people have just never written those priorities down, and would be surprised by what they reveal, particularly the gap between what they rank highest and what actually gets the hours.
For the example in this post, family scores highest (5), followed by sleep, meaningful work, and exercise (all 4). Learning and leisure come next (3). Paid work and chores appear near the bottom (1), not because they are unimportant but because their hours are largely fixed already and they do not need protecting. Doomscrolling scores negative, as an example of something not necessarily actually useful!
The specific numbers matter less than the ordering. The point is to know which things you would sacrifice last, and which ones you are currently sacrificing first.
The weights \( w_i \) are exactly the coefficients in the objective from earlier. Doubling \( w_i \) says “an hour of this is now worth twice as much,” and the solver will reach for it harder, up to its ceiling \( u_i \). For our model, the weights come directly from the “Matters” column of the values grid:
| Activity \(i\) | \(w_i\) |
|---|---|
| family | 5 |
| sleep | 4 |
| deep work | 4 |
| exercise | 4 |
| learning | 3 |
| leisure | 3 |
| paid work | 1 |
| chores | 1 |
| doomscrolling | −1 |
Weights can be negative too, for activities that actively cost you. Doomscrolling has \( w_i = -1 \), which means the optimizer, given any choice at all, drives it to its floor of zero.
The values clarification grid
So far this is abstract. Here is an exercise to help you work out your own set of values and deciding what is most important. I find this is a good exercise to do with a partner, too. It is sometimes called a values clarification grid, or a values matrix.
List the things you actually spend a week on, not the things you tell people you spend a week on. For each, score from 1 to 5 how much it genuinely matters to you, write one sentence about why it earns that score, and note roughly how many hours it currently gets. That third column is the gap between what you score 5 and what you actually fund with hours.
Here is a worked example. Make sure yours sums to 168.
| Activity | Matters (1–5) | Why it earns that score | Hrs/wk now |
|---|---|---|---|
| Family & close relationships | 5 | #1 priority | ~20 |
| Sleep | 4 | Essential for everything else. | ~57 |
| Meaningful work / craft | 4 | The work I would do even unpaid: writing, reading, thinking. | ~12 |
| Exercise | 4 | Compounds into everything; ignored at a slow, deferred cost. | ~5 |
| Learning | 3 | A core principle for my life and relationships. | ~3 |
| Genuine rest / leisure | 3 | Real rest, necessary for happiness. Video games, films, etc. | ~4 |
| Paid work (fixed) | 1 | Funds the whole operation. Valued, but already non-negotiable at 40. | 40 |
| Chores & admin | 1 | Necessary, joyless, has a stubborn minimum that will not go to zero. | ~20 |
| Doomscrolling | −1 | Feels like rest, costs like a tax. Actively negative on reflection. | ~7 |
Even with no further machinery, this table is useful. Look down the “matters” column and then across to “hours now,” and the mismatches jump out: things I claim to value at 4 getting two or three hours, things I value at 1 or below eating the evening.
But we are going to solve it, because the grid above is, almost exactly, the input to an optimization model. The “matters” column is the vector of weights \( w_i \). The activities are the index set \( A \). All that is missing is the bounds (the floors and ceilings) and a constraint or two to keep the solution realistic. So let us build it.
Turning the grid into a model
Here is the full thing, written out. We maximize weighted value across the week, subject to the hours adding up and every activity living inside its floor and ceiling.
The whole model on one page. Line one is the goal: maximize total value. “s.t.” means “subject to,” and the lines below it are the rules: the week sums to 168, every activity stays within its floor and ceiling, and all hours are whole non-negative integers.
Now the model in code. It uses PuLP, a readable Python modelling library that ships with a solver, so this runs as-is with pip install pulp. The data is lifted straight from the grid above.
The model in Python (PuLP)
import pulp
# --- Data, straight from the values grid -------------------------------------
# weight = how much an hour is worth to you (the "matters" column)
# (low, high) = the floor you won't drop below and the ceiling beyond which
# more hours are impossible or pointless
activities = {
# weight low high
"family": ( 5, 14, 28),
"sleep": ( 4, 49, 56), # 7 to 8 hours a night
"deep_work": ( 4, 0, 15), # meaningful work / craft
"exercise": ( 4, 0, 10),
"learning": ( 3, 0, 10),
"leisure": ( 3, 0, 20), # genuine rest
"paid_work": ( 1, 40, 40), # fixed by contract
"chores": ( 1, 7, 14), # stubborn minimum
"doomscroll": (-1, 0, 168), # actively negative
}
WEEK = 168
# --- Model -------------------------------------------------------------------
m = pulp.LpProblem("optimize_my_week", pulp.LpMaximize)
# Integer decision variable: hours per week on each activity
x = {
name: pulp.LpVariable(name, lowBound=lo, upBound=hi, cat="Integer")
for name, (w, lo, hi) in activities.items()
}
# Objective: total weighted value
m += pulp.lpSum(w * x[name] for name, (w, lo, hi) in activities.items())
# The week is finite and fully allocated
m += pulp.lpSum(x.values()) == WEEK
# --- Solve -------------------------------------------------------------------
m.solve(pulp.PULP_CBC_CMD(msg=False))
print("Status:", pulp.LpStatus[m.status])
for name in activities:
print(f" {name:11s} {int(x[name].value()):>4d} h")
print(f"Objective (weighted score, not hours): {int(pulp.value(m.objective))}")
What the solver says
Run it and the optimizer hands back a fully specified week:
Solver output
Status: Optimal
family 28 h
sleep 56 h
deep_work 15 h
exercise 10 h
learning 0 h
leisure 12 h
paid_work 40 h
chores 7 h
doomscroll 0 h
Objective (weighted score, not hours): 547
The 547 is a weighted score: each activity’s hours multiplied by its weight, summed across all nine. It has no unit and no ceiling; it exists solely to let the solver compare one allocation against another. Here is how the optimal week reshuffles against the current rough estimates from the grid:
| Activity | Now (hrs) | Solver (hrs) | Δ |
|---|---|---|---|
| Family | ∼20 | 28 | +8 |
| Sleep | ∼57 | 56 | −1 |
| Meaningful work | ∼12 | 15 | +3 |
| Exercise | ∼5 | 10 | +5 |
| Learning | ∼3 | 0 | −3 |
| Leisure | ∼4 | 12 | +8 |
| Paid work | 40 | 40 | 0 |
| Chores | ∼20 | 7 | −13 |
| Doomscrolling | ∼7 | 0 | −7 |
It drove family and sleep and meaningful work to their ceilings, because those carry the most weight per hour. It zeroed out doomscrolling without sentiment, because the weight is negative and nothing forces it above its floor. It pinned chores to the stubborn minimum of seven, because they are necessary but you told it they are nearly worthless, so it spends not one hour more.
The casualty is learning: it got zero hours. The floors alone (family, sleep, work, chores) eat 110 of the 168 before anything optional happens, and once the model had funded its highest-value activities up to their ceilings, only twelve hours were left to share out. That is the model telling you what your stated priorities cost. If a week with no learning in it horrifies you, the fix is not to argue with the solver. The fix is to go back and change a weight, because you have just discovered you value learning more than you claimed to!
Learning and leisure carry the same weight of 3, so the solver was genuinely indifferent between them: it poured all twelve into leisure and left learning at nothing, but it could just as correctly have done the reverse, or split them down the middle. This is called degeneracy: the model admitting that some choices make no difference to the objective. Which, I would argue, we should implement some kind of equality preference into the objective.
The Limits
The failure mode of this kind of thinking is taking it too seriously and trying to live inside a spreadsheet. Your life is not a linear program, and the places it refuses to be one are worth naming. Ultimately, these kind of solvers don't measure up to reality. If you're having a bad day, your "leisure" hours will need a serious and immediate bump up. If your sink floods and you need to clean out the kitchen cupboards due to spreading water, you can't ignore it because you don't have enough chores hours!
Value is not linear. The first hour with my partner and the fourteenth are not worth the same, especially when other things are falling to the side. Real value has diminishing returns, and a straight line does not. The model fakes this with ceilings (it caps activities before they get silly) but that is a workaround, not the truth.
And the world is uncertain. The model assumes you know your coefficients and your constraints with confidence, when in fact the hardest thing about a real life is that you mostly do not. Children get sick, work explodes, the long-planned thing falls through. A genuinely faithful model would be stochastic and re-solved constantly, which is just a mathematician’s way of describing what we already do, with some success, in our heads.
Most of all: some of the best things resist being a number at all. You cannot put a weight on love (wow, please quote this on my deathbed), or on a conversation that changes you, or on the afternoon you will think about for the rest of your life. This is nothing more than an exercise in learning a bit more about optimization and helping you consider your priorities.
The point isn’t the schedule
It was everything you had to figure out in order to ask the question: what you want, what you cannot change, and what each part of your life is actually worth to you. Sit and work out your priorities, say it out loud with a partner and work through it frequently and constantly reweight and re-evaluate.
Please do try the above table with your partner, or a friend. Sit down and really, honestly try to state what your priorities are and if you meet them or not. Specifically, think about things that are longer term goals that you haven't begun working on. Learning a language, an instrument, reading a book your friend kindly gifted you, walking your dog more, exercising for a specific goal, or quitting smoking. These long terms goals are tough to confront when we consider reality, how little time we have in week, or in a lifetime. Write it down on the list. If the outcome is that you spend one hour more than zero on something that you claim is deeply important to you, you're on your way. That is true, undeniable progress. Even just 1 hour is 1 hour more than last week.