Wednesday, November 19, 2025

Estimating population growth with Euler method

 

Motivation

Mathematical introductions to Euler method that we can find on the Internet require some insight to be transformed into working code. On the other hand, existing code samples are often convoluted and detached from the mathematical foundations of the method. My goal here is to present a really simple piece of code that solves a first order differential equation so that, without the use of any external libraries, anyone with basic understanding of Python and some interest in maths can understand the thing.
 

Mathematical foundation

Please refer to https://en.wikipedia.org/wiki/Euler_method and its First-order example paragraph. The problem I personally see with this paragraph is the use of the expotential function as the illustration of the first-order equation. I think it will be much easier to understand if we use something easier, something that can be easily connected to a real world phenomenon.
 

Population growth equation

A relatively easy equation is the one for population growth. Two terms that we need to define to reason about it are:

Simply put, the rate of natural increase (r) tells us how fast the population is growing, based on births and deaths. The capacity (K) is the limitation of the environment to carry a population - a maximum number that still allows for the resources, such as food and water, to be available to the population. The equation we are going to solve is:

dy/dx = rN (1 - N/K)

where N is the population size. The solution to this equation will model the population growth over time.


 

The chart shows nicely how the population grows and when it reaches the environment limit and flattens out.

 

Code pointers

Full Python code is available at: https://github.com/pgorak/population-growth-euler
 
makeSteps function is a top level wrapper that accepts the basic parameters:
  • number of steps of the Euler method to execute
  • step size (h)
  • the first order function
  • initial values of x and y

_makeSteps function actually performs the steps in a loop and appends the results to the lists of X and Y coordinates.

dxdy function is our first order function - it is dependent on the x and y values calculated in the prior steps. Note: some first order functions may use just x or just y, some may use both. For example, our population growth function only uses y, while the polynomial function would use just x.

The dxdy function is turned into a callable using functools.partial so that it can be passed as an argument to makeSteps and called.

Try playing with different functions - a polynomial example is provided (commented out) in the code and you can also try out your own functions, also using sin, cos, etc. In some cases you will need to adjust the initial values of x and y.

Wednesday, October 22, 2025

Guice servlet with managed access to a database

When I started learning Guice, I was not able to use the persistence feature of it: even though the official documentation provides some tips, there is no end-to-end example to demonstrate it. The thing I was looking for was a simple but complete flow where we have a method annotated with Guice's @Transactional and the method makes an update to a database using Guice's PersistService, without the need for the developer to programmatically commit the transaction or manage the EntityManager instance.

I started looking for the examples, but the result was very much similar - each article or Stackoverflow post had just some pieces of information, not enough on its own to present the full case.

After combining these pieces of information and doing lots of experiments, I was finally able to come up with a minimalist implementation of a servlet application that:

  • uses Guice for dependency injection
  • uses Guice for persistence / transaction management
  • makes a simple update to a database (in this case, Postgres)

The code is available on Github: https://github.com/pgorak/guice-servlet-db-example

and the project includes a tiny, dockerized Postgres DB.

One interesting finding that I made was that Guice only really acts upon the @Transactional annotation, if it is provided in the top level method. If the annotation is not at the top level, but it is provided in another, downstream method that is called by the top level one, then it does not work. It seems strange and it appears to me as a shortcoming, compared to the same annotation in Spring. Accidentally, it turned out to be the same finding that Kohei Nozaki described in his blog: https://nozaki.me/roller/kyle/entry/testing-guice-persist-nested-transactional


Wednesday, June 25, 2025

Concurrency with Python's asyncio

Let's imagine a process that downloads a file from the Internet. Each time the process detects it downloaded the next 20% of the whole, it prints a message. The output from this process could look like this:

processA downloaded 20%    Wed Apr 16 10:19:46 2025
processA downloaded 40%    Wed Apr 16 10:19:47 2025
processA downloaded 60%    Wed Apr 16 10:19:51 2025
processA downloaded 80%    Wed Apr 16 10:19:54 2025
processA downloaded 100%  Wed Apr 16 10:19:59 2025

Formally speaking, this output is called the trace.

Now let's imagine we have two processes that do something similar and they work concurrently. Each downloads a different file (possibly from a different source) and the time it takes to download each file will differ. When they work concurrently and they still print their trace, we will get something like this:

processA downloaded 20%    Wed Apr 16 10:19:46 2025
processB downloaded 20%    Wed Apr 16 10:19:46 2025
processA downloaded 40%    Wed Apr 16 10:19:47 2025
processB downloaded 40%    Wed Apr 16 10:19:49 2025
processA downloaded 60%    Wed Apr 16 10:19:51 2025
processA downloaded 80%    Wed Apr 16 10:19:54 2025
processB downloaded 60%    Wed Apr 16 10:19:54 2025
processA downloaded 100%  Wed Apr 16 10:19:59 2025
processB downloaded 80%    Wed Apr 16 10:20:00 2025
processB downloaded 100%  Wed Apr 16 10:20:05 2025

Note that the above is just one possible trace of the concurrent execution of these two processes. There could be many traces, depending of the progress of the download in each process (252 possible traces).

This behavior can be demonstrated nicely with a simple Python program using asyncio. It is a toy program in the sense that it does not really download anything, instead it emulates that some random time has elapsed for the download of part of the data. But more importantly, it actually employs two concurrent tasks that execute together and produce a similar trace.

The complete program: 

import asyncio
from random import choice
from time import ctime

async def download(name: str) -> None:
    for k in range(1,6):
        await asyncio.sleep(choice([1,3,5]))
        print(f'{name} downloaded {k*20}%    {ctime()}')

async def main():
    taskA = asyncio.create_task(download('processA'))
    taskB = asyncio.create_task(download('processB'))
    await taskA
    await taskB
    
if __name__ == '__main__':
    asyncio.run(main())

Explanatory notes:

The download function is  the one that is actually the body of the task. It emulates some random wait time for downloading a chunk of data and then prints the current download status. Please note that it accepts a parameter, in this case the task name and that the definition is prepended with async.

Inside main we spawn two tasks. Both are based on the download function and will do exactly what it does, but they are spawned with different names. The create_task calls are non-blocking. Each will spawn the new asynchronous task and let the program continue.

Once both tasks are started, the main function needs to wait until both tasks have completed. Try running the program without these two awaits and see what happens. Also try commenting out just one of the awaits and run the program a few times - you should be able to note that the program terminates before the non-awaited task has completed.

This program is aimed to be a clear and concise example. It could be expanded to really do something that requires non-deterministic wait time, such as file download, REST API calls, etc. and also to use more than two tasks. However, the basic idea remains the same: with asyncio you can achieve asynchronous processing through tasks it can all be expressed very nicely, in the way that is much more readable than in most of the other programming languages that implemented the asynchronous processing on top of what they originally had. 

See also