How to Over Engineer a Todo App (The Zenith Gradient Algorithm)
Tags: math, softwareengineering, webdev
Published: 2024-05-31 19:25:58

## Motivation
Let’s say for example you have 4 tasks to do in a given day: Work on an essay, do some math homework, edit a video, and study for a physics exam, and let’s also assume that you have 6 hours in total to spend on all these tasks. The question is: how should you best allocate time to each one of these tasks to maximize your productivity? A rudimentary approach would be to allocate time arbitrarily or allocate an equal amount of time to each task without taking into account any factors like the difficulty of the task etc. In this case, you could simply allocate 1.5 hours to each task and call it a day, but could you do better? What if you instead allocated 1 hour for working on the essay, 0.5 hours for the math homework, 2.5 hours for editing the video and 2 hours for studying physics? You would still spend a total of 6 hours, but would this be better? i.e. Would you be more productive? How can we quantify these decisions? How could we build a todo app that does this computation for us?

## Defining Productivity

For a given task, let ρ(t) be the amount of progress we have made at time t, then productivity p(t) can be defined as the amount of progress made per unit time i.e. p(t) = dρ/dt (Productivity is the time derivative of progress). If we make a lot of progress really quickly, then we are more productive, if our progress doesn’t change with respect to time, then we aren’t productive at all, so this is a reasonable definition for productivity.

## Finding a Model

While doing a task, productivity as a function of time naturally has the shape of a Poisson Distribution, it starts at some initial value, then increases to some maximum point (this can be the mathematical definition of flow state, i.e. flow state can be defined as a time when we’re most productive), then decreases as we lose energy. A good model for this type of behavior is the function

![Productivity function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kcv2jidmth9tpf45szgk.png)


![Productivity Graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dcuczwy16cwei31847f.png)

This curve can be parameterized by the effort of the task E, the enjoyability of the task β, and the time it takes to reach flow state ϕ. As mentioned above, flow state can be defined as the time when productivity reaches a maximum. To calculate this value, we can set dp/dt = 0 and solve for t. This calculation results in t=1/k. We can now set this value of t equal to ϕ and solve for k, which results in k=1/ϕ.

We can express ϕ as a function of E and β.

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hvd60x7x4yhirb823l64.png)

Pinpointing this function exactly would be complicated. Instead, we can approximate ϕ as a linear function

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pbtuxm3066y512cq08r4.png)


where c₁, c₂ and c₃ are constants that vary from person to person and are within a range such that ϕ>0.

The initial productivity p0 can be defined

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzw2jz3hdisvwnq7w002.png)

we typically have a harder time starting higher effort tasks compared to lower effort tasks and hence our starting productivity decreases as the effort of the task increases, we also tend to have an easier time starting tasks that we really enjoy, so our starting productivity increases as the enjoyability increases.

Increasing the parameter ‘a’ increases the global maximum of the function and hence increases the value of our peak productivity. We can try to quantify how ‘a’ depends on the parameters E and β by thinking of how our peak productivity (flow state) changes depending on the effort of the task and how much we enjoy doing it. Let’s use a video game as an example, when playing a low effort video game, the flow state we experience won’t feel that much different than how we feel on a regular basis, in contrast, when playing a high effort competitive video game, the flow state we experience will feel almost magical compared to any other time, especially if we really enjoy the game. This tells us that higher effort tasks that we really enjoy corresponds to a higher peak productivity. A good model for this is the function

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wkgls5vrwjur9rhsmldq.png)

Putting this all together we have

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3v68ysoubyq91ulob98b.png)

## Defining The Parameter Boundaries

In the previous section we defined the time it takes to reach flow state ϕ as

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pbqju5rrwk7m1afw2ls2.png)

where c₁, c₂ and c₃ are constants that vary from person to person. For ϕ to be non negative, we can define a fixed range for E and β. We can define some intermediate variables Eᵤ and βᵤ to be the effort and the enjoyability respectively that the user provides. For consistency, both of these values will range from 1 to 10 and will then be mapped linearly to their respective ranges, i.e. E (the true value of effort) is a linear function of Eᵤ and β (the true value of enjoyability) is a linear function of βᵤ.

### The Boundary of Effort

Experimentally, it was determined that a good range for E is 1 ≤ E ≤ 5, we can now linearly map the range of Eᵤ (the intermediate value of effort) from 1 to 10 down to 1 to 5 using the function

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zvlb0fos4utv83bdcs9e.png)

### The Boundary of Enjoyability

Similarly, a good range for β is 1 ≤ β ≤ 2, we can linearly map the range of βᵤ from 1 to 10 down to 1 to 2 using the function

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dpzl95irs8mu0fv56dip.png)

## User Dependent Constants

Now we will explore how c₁, c₂ and c₃ can be determined.

For each task (Task i), a stopwatch can be used to measure the time until flow state ϕ (the time it takes to get in the “zone”). This will give us data points

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qvqgny98konwlu71bmhw.png)

where Eᵢ is the effort of task i and βᵢ is the enjoyability of task i.

We can then use Linear Least Squares approximation to find the best fit plane to the data which results in

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rf7z0embrz7j2i10pxjb.png)

**NB**: c₁, c₂ and c₃ will be updated after a new data point has been provided.

## When to Stop Doing a Task

Let’s assume you have the task of studying for a math exam, and you’ve determined that the effort of this task on a scale from 1 to 10 is about 7 (Eu = 7 → E = 3.67), the enjoyability is 3 (βu = 3 → β = 1.22). Let’s also assume that your user dependent constants are c1 = 0.56, c2 = −0.24, and c3 = 0 your estimated time until flow state will then be

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/he3vnwkguko2ac35s97d.png)

and your productivity curve is

![Productivity graph](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsrtusgffrmvmuyhvf53.png)

Now the question is, how long should you spend doing this task to maximize productivity? If you study for too long, you will become burnt out and start experiencing diminishing returns, study for too little and you risk not getting enough value out of that session. There is a sweet spot, and intuitively we know it lies some time after you reach flow state… but how long after? To answer this, we need a measure of how productive you are on some time interval, for the sake of example, let’s say the first 30 minutes into studying. A good measure for this is the average of p(t) between t = 0 and t = 0.50, which can be calculated by:

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6dwrswd7yoo6afafacpw.png)

We can compare this to a later time interval, let’s say between 8 and 8 and a half hours.

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7rh3ajdvd8399d0ic0iu.png)

As we can see, the first 30 minutes into studying was much more valuable than 30 minutes a couple hours later. Now, we can define

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u6q59ofdlrgj5q8gfbz5.png)

We can finally find the global maximum of this function to get the optimal time you should spend studying to maximize productivity

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z9jf580mlg79lyvz4duq.png)

Solving for t numerically, we find that t ≈ 3.16. So the optimal amount of time you should spend studying is 3 hours and 10 minutes.

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ks5e74we8uf2b4r28zvl.png)

## Generalizing

If we have n tasks to complete in T hours and are given

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzser80xzyjk5dc6jcwy.png)

the effort vector, and

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/76f7garift24rrllht87.png)

the enjoyability vector where Eᵢ is effort of task i, and βᵢ is the enjoyability of task i.

We cane define

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pjtibme2u5gdm7tga2ck.png)

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aabrwr9ux4bww37clxuw.png)

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/930vkxrhb0wp8m2lgrle.png)

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8beyzy5vmjirx9t9dfam.png)

Let P(**t**) be the total productivity for the day, where **t** = ⟨t1, t2, . . . , tn⟩, and tᵢ is the time spent doing task i. P(**t**) can be defined as the sum of the average productivity for each task.

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ltqaljozq73mgt15fu3f.png)

We can now maximize this function under the constraint that

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fdbnxs7leyz4czoisdte.png)

using the method of Lagrange multipliers.

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/my8szzoagz62z7kj7a9i.png)

## Solving The System of Equations

Let us revisit the example that we started with: “You have 4 tasks to do in a given day: Work on an essay (Task 1), do some math homework (Task 2), edit a video (Task 3), study for a physics exam (Task 4), and let’s also assume that you have 6 hours in total to spend on all these tasks. The question is, how should you best allocate time to each one of these task to maximize productivity?” Each of these tasks have an associated effort and enjoyability, we can define:

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yezjf7pwptfkwpkj7qbf.png)

This gives us

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5dnuwrpv1ry57agv1lru.png)

Therefore,

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gw4v0jhrx3vfmd3t7rtg.png)

Solving this system numerically results in the solution:

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thdgo1eetwyvpgc3ojx2.png)

So, to maximize your productivity for the day, you should spend 0.70 hours (42 minutes) working on the essay, 1.84 hours (1 hour and 50 minutes) doing the Math homework, 1.11 hours (1 hour and 7 minutes) editing the video and 2.31 hours (2 hours and 21 minutes) studying Physics.

We can now compare this to the rudimentary approach mentioned at the beginning, where you would arbitrarily allocate time. For example, let’s say you allocated 2.5 hours for the essay, 2 hours for math, 0.5 hours for editing the video, and 1 hour for studying physics.

P(2.5, 2, 0.5, 1) ≈ 5.16, while P(0.70, 1.84, 1.11, 2.35) ≈ 6.13 which means you would increase your productivity for the day by about 19% by using this model.

## Sanity Check

If we have a list of tasks to complete that all have the same level of effort and enjoyment, intuitively we would expect that it would be best to spend an equal amount of time on each task since there would be no reason to prioritize one task over another. Mathematically, this states that if we solve the non-linear system above with

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zz93r2cm3jsbtzt6k8l.png)

where

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqn6j7zkinujj3xu3jt7.png)

for some value of E and β, then the solution to the system will be

![Equation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ot3awip06f8u39f65etv.png)

The proof of this is left as an exercise for the reader :)

## The Final Product

I’ve been developing this app for almost 2 years. The model described above has been fully implemented and you can try it out for free at: https://www.acumenweb.app/ 

![Product image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w56s8staoki50me9k2ir.jpeg)

A demo of the app can be view at: https://youtu.be/DcBo8AAKzLw

Dr Tom Crawford from the **Tom Rocks Maths** YouTube channel has also made a video covering the algorithm: https://youtu.be/vqbGIfjKmuU

Primeagen has made a video reacting to the algorithm: https://youtu.be/egVO61490h8

If you have any questions about the model or feature suggestions, you can join the discord and we can discuss: https://discord.gg/myFa5SKA5P