Performance, Convergence, and Likelihood Validation: R pomp vs. pypomp

Published

June 25, 2026

Introduction

This report compares the performance, parameter convergence, and likelihood evaluation of the Dhaka cholera epidemic model using two different optimization pipelines from the pypomp package:

  1. IF2 only (Iterated Filtering 2 / IF2)
  2. IF2 + Train (IFAD) (Iterated Filtering with Automatic Differentiation)

The Dhaka cholera model is an epidemic model describing cholera dynamics in Dhaka, Bangladesh.

Parameter Definitions

  • gamma: Recovery rate from infection.
  • m: Cholera mortality rate.
  • rho: Reporting rate of cholera cases.
  • epsilon: Rate of waning of immunity for inapparent infections.
  • c: Fraction of infections that lead to severe infection.
  • alpha: Non-linear transmission factor.
  • delta: Cholera-induced mortality rate.
  • beta_trend: Long-term secular trend in transmission.
  • sigma: Environmental noise intensity.
  • tau: Measurement noise (overdispersion parameter).
  • bs1 - bs6: Spline coefficients modeling seasonal transmission rates.
  • omegas1 - omegas6: Spline coefficients for seasonal environmental reservoir.
  • S_0, I_0, Y_0, R1_0, R2_0, R3_0: Initial compartment fractions.

For this test, we fix the values of Y0, c, alpha, delta, and rho.

Because the Dhaka model has a very fast transition process but many transition simulator calls per observation, it is highly sensitive to computational overhead. If the wall clock time is ever too long, it could be a sign that this overhead is excessive.

A more thorough version of this analysis is available here.


Setup & Theme Configuration

Show Imports & Theme Configuration
import os
import logging
import pickle
from datetime import datetime
import numpy as np
import pandas as pd
from plotnine import *
from IPython.display import display, HTML, Markdown

# Hide the noisy JAX CUDA initialization error on machines without a GPU
logging.getLogger("jax._src.xla_bridge").setLevel(logging.CRITICAL)

import pypomp as pp
import jax

print(f"Report execution time: {datetime.now()}")


# Setup theme and color palettes
def theme_premium():
    return theme_minimal(base_size=11) + theme(
        plot_title=element_text(face="bold", size=12, color="#2c3e50"),
        axis_title=element_text(face="bold", size=10, color="#34495e"),
        axis_text=element_text(size=9, color="#2c3e50"),
        legend_title=element_text(face="bold", size=9, color="#34495e"),
        legend_text=element_text(size=9, color="#2c3e50"),
        legend_position="bottom",
        strip_background=element_rect(fill="#f8f9fa", color="none"),
        strip_text=element_text(face="bold", size=9, color="#2c3e50"),
        panel_grid_major=element_line(color="#eaeded"),
        panel_grid_minor=element_line(color="#f4f6f6"),
    )


def scale_color_premium():
    return scale_color_manual(
        values={
            "IF2": "#3498db",
            "IFAD": "#1abc9c",
            "mif": "#3498db",
            "train": "#1abc9c",
            "Python (pypomp)": "#1abc9c",
            "R (pomp)": "#e74c3c",
        }
    )


def scale_fill_premium():
    return scale_fill_manual(
        values={
            "IF2": "#3498db",
            "IFAD": "#1abc9c",
            "mif": "#3498db",
            "train": "#1abc9c",
            "Python (pypomp)": "#1abc9c",
            "R (pomp)": "#e74c3c",
        }
    )


def display_html_table(df, title=None):
    html_str = df.to_html(index=False, classes="table table-striped table-hover")
    if title:
        display(Markdown(f"#### {title}"))
    display(HTML(html_str))
Report execution time: 2026-06-25 12:37:39.046245

System Configurations & Metadata

Hardware & Hardware Mappings
  • GPU Model Used for Parameter Estimation (MIF/Train): NVIDIA RTX 6000 (Blackwell)
  • GPU Model Used for Particle Filter Evaluation: NVIDIA Tesla V100
IF2 only Pomp Object Metadata:
Model Initialization Metadata:
------------------------------
pypomp version: 0.4.6.0
JAX version:    0.9.0.1
Python version: 3.12.13
Platform info:  Linux-4.18.0-553.123.1.el8_10.x86_64-x86_64-with-glibc2.28
Default device: gpu
Created at:     2026-06-17T15:47:01.252367+00:00

IF2 + Train (IFAD) Pomp Object Metadata:
Model Initialization Metadata:
------------------------------
pypomp version: 0.4.6.0
JAX version:    0.9.0.1
Python version: 3.12.13
Platform info:  Linux-4.18.0-553.123.1.el8_10.x86_64-x86_64-with-glibc2.28
Default device: gpu
Created at:     2026-06-17T15:46:55.951364+00:00
IF2 only Summary:
Basics:
-------
Number of observations: 600
Number of time steps: 12000
Number of parameters: 28
Number of parameter sets: 1

Results History:
----------------
[0] MIF Result:
Method: mif
Number of parameter sets: 100
Number of particles (J): 5000
Number of iterations (M): 650
Resampling threshold: 0
Number of monitors: 0
Cooling fraction (a): 0.8
Execution time: 849.5330967903137 seconds

Top 5 Results:
    theta_idx       logLik  se      gamma         m  rho    epsilon    c  alpha  delta  beta_trend     sigma       tau       bs1       bs2       bs3       bs4       bs5       bs6   omegas1   omegas2   omegas3   omegas4    omegas5   omegas6       S_0       I_0  Y_0      R1_0      R2_0      R3_0
68         68 -3750.151855 NaN  21.964891  0.064317  0.0  19.285217  1.0    1.0   0.02   -0.004042  3.202443  0.228832  1.080825  6.066805 -2.709712  4.180920  3.432794  4.449792 -2.632095 -1.606167 -3.121915 -4.248219 -11.145409 -4.149855  0.177239  0.426731  0.0  0.015628  0.002518  0.377883
77         77 -3751.127197 NaN  20.656321  0.068288  0.0  18.823858  1.0    1.0   0.02   -0.004685  3.071877  0.206632  0.879721  6.247706 -4.229592  4.247345  3.324046  4.412554 -3.180451 -1.009576 -4.022504 -3.781211  -9.740456 -3.054374  0.327544  0.341226  0.0  0.028058  0.217750  0.085422
39         39 -3751.448486 NaN  18.311306  0.061893  0.0  12.584141  1.0    1.0   0.02   -0.004847  2.992834  0.244172  0.781054  6.170775 -3.655614  4.173553  3.277765  4.431059 -2.622661 -1.360682 -5.459607 -2.189872 -14.956080 -4.405107  0.045564  0.313810  0.0  0.254939  0.183061  0.202625
59         59 -3751.540283 NaN  17.173849  0.054944  0.0  14.742928  1.0    1.0   0.02   -0.007332  3.274948  0.222007  0.470507  6.475519 -4.491791  4.285765  3.239773  4.486603 -2.584773 -1.248865 -4.166919 -3.425526  -9.872215 -3.421314  0.015579  0.300452  0.0  0.010116  0.141214  0.532639
36         36 -3751.803711 NaN  20.036077  0.045526  0.0  36.318157  1.0    1.0   0.02   -0.005186  3.292320  0.233202  0.856999  6.201374 -3.246956  4.015867  3.392638  4.432448 -2.039955 -1.055448 -3.622124 -3.308278  -8.825769 -4.762496  0.004691  0.631125  0.0  0.090433  0.175321  0.098429

[1] PFILTER Result:
Method: pfilter
Number of parameter sets: 100
Number of particles (J): 5000
Number of replicates: 36
Resampling threshold: 0
Execution time: 26.93988800048828 seconds

Top 5 Results:
    theta_idx       logLik        se      gamma    epsilon  rho         m    c  beta_trend       bs1       bs2       bs3       bs4       bs5       bs6     sigma       tau  alpha     delta       S_0       I_0  Y_0      R1_0      R2_0      R3_0   omegas1   omegas2   omegas3   omegas4    omegas5   omegas6
58         58 -3748.593112  0.138292  19.427231  12.632298  0.0  0.062359  1.0   -0.003322  0.951157  6.229884 -3.592779  4.161263  3.350472  4.456390  3.150334  0.218260    1.0  0.019998  0.112169  0.372486  0.0  0.046147  0.298476  0.170722 -2.201128 -2.384608 -3.703540 -3.613372 -11.210645 -5.267404
68         68 -3748.829823  0.156268  21.964661  19.285112  0.0  0.064317  1.0   -0.004042  1.080825  6.066812 -2.709714  4.180918  3.432804  4.449782  3.202444  0.228831    1.0  0.019998  0.177242  0.426728  0.0  0.015631  0.002519  0.377880 -2.632092 -1.606167 -3.121928 -4.248227 -11.145434 -4.149848
39         39 -3750.204397  0.196137  18.311197  12.584039  0.0  0.061893  1.0   -0.004847  0.781056  6.170779 -3.655602  4.173546  3.277767  4.431048  2.992827  0.244171    1.0  0.019998  0.045560  0.313821  0.0  0.254930  0.183045  0.202644 -2.622662 -1.360683 -5.459601 -2.189871 -14.956100 -4.405100
98         98 -3750.534565  0.165392  24.685760  29.432806  0.0  0.065043  1.0   -0.005106  1.771510  5.618901 -1.030614  3.997231  3.581449  4.340600  3.132322  0.222317    1.0  0.019998  0.022417  0.476428  0.0  0.012351  0.244612  0.244192 -1.470560 -2.997992 -2.450732 -4.803770  -9.127362 -5.902627
77         77 -3750.785620  0.167869  20.656410  18.823885  0.0  0.068288  1.0   -0.004685  0.879722  6.247713 -4.229591  4.247355  3.324033  4.412556  3.071879  0.206632    1.0  0.019998  0.327555  0.341218  0.0  0.028056  0.217756  0.085416 -3.180452 -1.009576 -4.022506 -3.781212  -9.740446 -3.054368

[2] PFILTER Result:
Method: pfilter
Number of parameter sets: 1
Number of particles (J): 5000
Number of replicates: 36
Resampling threshold: 0
Execution time: 7.793874502182007 seconds

Top 5 Results:
   theta_idx       logLik        se      gamma    epsilon  rho         m    c  beta_trend       bs1       bs2       bs3       bs4       bs5      bs6     sigma      tau  alpha     delta       S_0       I_0  Y_0      R1_0      R2_0      R3_0   omegas1   omegas2  omegas3   omegas4    omegas5   omegas6
0          0 -3748.981092  0.156376  19.427231  12.632298  0.0  0.062359  1.0   -0.003322  0.951157  6.229884 -3.592779  4.161263  3.350472  4.45639  3.150334  0.21826    1.0  0.019998  0.112169  0.372486  0.0  0.046147  0.298476  0.170722 -2.201128 -2.384608 -3.70354 -3.613372 -11.210645 -5.267404


IF2 + Train (IFAD) Summary:
Basics:
-------
Number of observations: 600
Number of time steps: 12000
Number of parameters: 28
Number of parameter sets: 1

Results History:
----------------
[0] MIF Result:
Method: mif
Number of parameter sets: 100
Number of particles (J): 5000
Number of iterations (M): 175
Resampling threshold: 0
Number of monitors: 0
Cooling fraction (a): 0.8
Execution time: 233.29161167144775 seconds

Top 5 Results:
    theta_idx       logLik  se      gamma         m  rho    epsilon    c  alpha  delta  beta_trend     sigma       tau       bs1       bs2       bs3       bs4       bs5       bs6   omegas1   omegas2   omegas3   omegas4    omegas5   omegas6       S_0       I_0  Y_0      R1_0      R2_0      R3_0
27         27 -3762.640381 NaN  24.212139  0.068762  0.0  11.126743  1.0    1.0   0.02   -0.005698  3.129986  0.245831  1.307654  5.736670 -1.176570  3.782749  3.643375  4.370105 -0.415357 -3.289375 -3.348756 -3.691118 -12.079140 -8.434428  0.116589  0.421890  0.0  0.063350  0.389191  0.008981
90         90 -3762.901855 NaN  21.772480  0.045010  0.0  28.155897  1.0    1.0   0.02   -0.004771  2.964030  0.220028  1.585946  5.801874 -2.280165  3.846111  3.525166  4.219296 -2.598875 -1.394280 -3.436198 -3.486423  -9.764434 -5.964502  0.040799  0.606775  0.0  0.045509  0.091340  0.215578
68         68 -3764.556885 NaN  21.393864  0.075635  0.0   7.855066  1.0    1.0   0.02   -0.002585  3.183395  0.212659  1.620270  5.881130 -2.707138  3.577305  3.667798  3.906045 -3.162070 -2.671127 -3.589335 -4.842529  -9.321199 -3.464468  0.090925  0.385414  0.0  0.015251  0.005168  0.503242
98         98 -3764.895996 NaN  17.297489  0.039995  0.0  16.608639  1.0    1.0   0.02   -0.005348  3.245703  0.263624  0.260745  6.563428 -4.101738  3.884881  3.315730  4.409178 -1.928176 -2.005364 -4.946624 -2.491831  -9.649882 -4.624081  0.031480  0.463317  0.0  0.006049  0.163789  0.335365
70         70 -3767.401855 NaN  18.442581  0.066556  0.0   8.557260  1.0    1.0   0.02   -0.007378  2.762660  0.286938  0.338371  7.020250 -6.428145  3.892280  3.396882  4.297029 -2.050196 -3.740616 -6.380733 -1.944295 -12.003162 -3.405320  0.012315  0.469796  0.0  0.025668  0.448931  0.043291

[1] TRAIN Result:
Method: train
Number of parameter sets: 100
Optimizer: Adam(clip_norm=None, scale=False, ls=False, c=0.1, max_ls_itn=10, beta1=0.9, beta2=0.999, epsilon=1e-08)
Number of particles (J): 5000
Number of iterations (M): 175
Learning rate (eta): LearningRate(
    'gamma': [0.005 ... 0.002504] (len=175)
    'epsilon': [0.01 ... 0.005008] (len=175)
    'rho': [0 ... 0] (len=175)
    'm': [0.01 ... 0.005008] (len=175)
    'c': [0 ... 0] (len=175)
    'alpha': [0 ... 0] (len=175)
    'delta': [0 ... 0] (len=175)
    'beta_trend': [0.005 ... 0.002504] (len=175)
    'bs1': [0.01 ... 0.005008] (len=175)
    'bs2': [0.01 ... 0.005008] (len=175)
    'bs3': [0.01 ... 0.005008] (len=175)
    'bs4': [0.01 ... 0.005008] (len=175)
    'bs5': [0.01 ... 0.005008] (len=175)
    'bs6': [0.01 ... 0.005008] (len=175)
    'sigma': [0.005 ... 0.002504] (len=175)
    'tau': [0.005 ... 0.002504] (len=175)
    'omegas1': [0.01 ... 0.005008] (len=175)
    'omegas2': [0.01 ... 0.005008] (len=175)
    'omegas3': [0.01 ... 0.005008] (len=175)
    'omegas4': [0.01 ... 0.005008] (len=175)
    'omegas5': [0.01 ... 0.005008] (len=175)
    'omegas6': [0.01 ... 0.005008] (len=175)
    'S_0': [0.005 ... 0.002504] (len=175)
    'I_0': [0.005 ... 0.002504] (len=175)
    'Y_0': [0 ... 0] (len=175)
    'R1_0': [0.005 ... 0.002504] (len=175)
    'R2_0': [0.005 ... 0.002504] (len=175)
    'R3_0': [0.005 ... 0.002504] (len=175)
)
Discount factor (alpha): 0.97
Resampling threshold: 0
Cooling factor for alpha: 1.0
Execution time: 560.8103060722351 seconds

Top 5 Results:
    theta_idx       logLik  se      gamma    epsilon  rho         m    c  beta_trend       bs1       bs2       bs3       bs4       bs5       bs6     sigma       tau  alpha     delta       S_0       I_0  Y_0      R1_0      R2_0      R3_0   omegas1   omegas2   omegas3   omegas4    omegas5   omegas6
13         13 -3743.760498 NaN  20.251841  20.245831  0.0  0.058517  1.0   -0.004255  1.002764  6.091524 -3.056101  4.008092  3.441768  4.376330  3.097749  0.225833    1.0  0.019998  0.062156  0.388545  0.0  0.064601  0.011323  0.473375 -2.774055 -1.373357 -4.143573 -3.222554 -11.613696 -2.826942
93         93 -3743.803223 NaN  20.815708  11.517911  0.0  0.077860  1.0   -0.004169  1.148633  6.019136 -2.875453  4.036393  3.436682  4.358935  3.067118  0.223425    1.0  0.019998  0.085510  0.321897  0.0  0.170926  0.409102  0.012565 -2.834315 -2.093054 -4.016954 -3.947895 -10.905134 -3.634035
81         81 -3744.193115 NaN  23.100718  14.865847  0.0  0.073935  1.0   -0.004094  1.419149  5.859457 -1.853224  4.055012  3.516918  4.379109  3.001645  0.233989    1.0  0.019998  0.073221  0.346280  0.0  0.413882  0.010512  0.156105 -1.659672 -3.747810 -3.068995 -4.482842 -10.760008 -4.952383
68         68 -3744.244141 NaN  21.990341  15.237506  0.0  0.071275  1.0   -0.004395  1.375314  5.839983 -2.113782  3.987557  3.511476  4.360020  3.089364  0.221977    1.0  0.019998  0.047695  0.333169  0.0  0.090939  0.011383  0.516814 -2.594796 -2.174549 -3.634304 -4.118052 -10.333586 -3.848638
75         75 -3744.398682 NaN  19.104820  12.249605  0.0  0.069862  1.0   -0.004964  0.682902  6.417171 -4.329762  4.173231  3.311105  4.433523  2.996027  0.233189    1.0  0.019998  0.000084  0.356255  0.0  0.491022  0.002095  0.150543 -2.925986 -1.823512 -4.546454 -3.141474 -12.645369 -2.854324

[2] PFILTER Result:
Method: pfilter
Number of parameter sets: 100
Number of particles (J): 5000
Number of replicates: 36
Resampling threshold: 0
Execution time: 26.99966263771057 seconds

Top 5 Results:
    theta_idx       logLik        se      gamma    epsilon  rho         m    c  beta_trend       bs1       bs2       bs3       bs4       bs5       bs6     sigma       tau  alpha     delta       S_0       I_0  Y_0      R1_0      R2_0      R3_0   omegas1   omegas2   omegas3   omegas4    omegas5   omegas6
78         78 -3743.999812  0.262546  23.491337  15.381614  0.0  0.075562  1.0   -0.004103  1.568382  5.678653 -1.430605  3.977406  3.589521  4.342077  3.098966  0.223255    1.0  0.019998  0.191345  0.328206  0.0  0.148732  0.305311  0.026406 -2.473709 -2.434286 -3.477571 -4.320254 -10.403983 -4.168930
68         68 -3744.008675  0.126527  21.990341  15.237506  0.0  0.071275  1.0   -0.004395  1.375314  5.839983 -2.113782  3.987557  3.511476  4.360020  3.089364  0.221977    1.0  0.019998  0.047695  0.333169  0.0  0.090939  0.011383  0.516814 -2.594796 -2.174549 -3.634304 -4.118052 -10.333586 -3.848638
90         90 -3744.234947  0.174754  22.029831  16.935524  0.0  0.068251  1.0   -0.004051  1.320705  5.881327 -2.116252  3.991364  3.496524  4.370700  3.091169  0.225722    1.0  0.019998  0.031103  0.356098  0.0  0.170418  0.187875  0.254506 -2.434963 -2.120219 -3.599538 -4.046407 -10.352216 -3.820924
4           4 -3744.242803  0.131772  21.988941  15.359138  0.0  0.070401  1.0   -0.004348  1.340430  5.872958 -2.084243  4.004765  3.515966  4.363273  3.097216  0.225482    1.0  0.019998  0.103011  0.352037  0.0  0.256992  0.267501  0.020459 -2.367638 -2.323117 -3.519745 -4.200439  -9.938107 -3.979023
47         47 -3744.316558  0.110903  21.695400  13.166071  0.0  0.074918  1.0   -0.004417  1.270838  5.905948 -2.296511  4.028853  3.478615  4.360231  3.054636  0.227493    1.0  0.019998  0.068877  0.350135  0.0  0.469205  0.047441  0.064342 -2.349479 -2.504070 -3.674402 -4.092130 -10.673473 -4.147773

[3] PFILTER Result:
Method: pfilter
Number of parameter sets: 1
Number of particles (J): 5000
Number of replicates: 36
Resampling threshold: 0
Execution time: 7.8361921310424805 seconds

Top 5 Results:
   theta_idx      logLik        se      gamma    epsilon  rho         m    c  beta_trend       bs1       bs2       bs3       bs4       bs5       bs6     sigma       tau  alpha     delta       S_0       I_0  Y_0      R1_0      R2_0      R3_0   omegas1   omegas2   omegas3   omegas4    omegas5  omegas6
0          0 -3744.07772  0.212155  23.491337  15.381614  0.0  0.075562  1.0   -0.004103  1.568382  5.678653 -1.430605  3.977406  3.589521  4.342077  3.098966  0.223255    1.0  0.019998  0.191345  0.328206  0.0  0.148732  0.305311  0.026406 -2.473709 -2.434286 -3.477571 -4.320254 -10.403983 -4.16893

Performance & Runtimes

The tables below display the computational runtimes across different stages of the estimation algorithm for the two configurations.

Validation Expectation

The total time to run the IF2-only configuration should take a bit longer than the IFAD configuration, as part of the point of this report is to demonstrate that IFAD yields better log-likelihoods in the same or less time.

Furthermore, we should observe that train runs no more than 3 times longer than IF2 per iteration.

IF2 only - Step-by-Step Runtimes

method time
mif 849.533097
pfilter 26.939888
pfilter 7.793875

Total IF2 execution time: 884.27 seconds

IF2 + Train (IFAD) - Step-by-Step Runtimes

method time
mif 233.291612
train 560.810306
pfilter 26.999663
pfilter 7.836192

Total IF2 + Train execution time: 828.94 seconds


LogLik Summary Statistics

Final pfilter logLik by source

Validation Expectation

We expect a maximum IFAD log-likelihood around -3744.0 and a maximum IF2 log-likelihood around -3748.5.

LogLik Summary Statistics by Pipeline

Source N Mean Std Min Median Max
IF2 only 100 -3762.57 14.53 -3818.13 -3756.66 -3748.59
IF2 + Train (IFAD) 100 -4383.87 3620.57 -24868.00 -3746.36 -3744.00

IF2 only traces

Validation Expectation

The IF2 traces shouldn’t look terrible. Some of the parameters in this model are not well-identified, so it’s normal for IF2 to struggle to converge tightly for some parameters.


IF2 + train traces

Validation Expectation

For most, but not all parameters, we should see the traces start to converge more tightly after the search switches from mif to train.


Comparison: MIF vs train

This section directly compares the final output quality between the two pipelines.

LogLik (density)

Validation Expectation

IFAD tends to yield better parameter estimates with lower Monte Carlo variance compared to IF2 alone, so we expect to see the better log-likelihood values for IFAD overall.

Final parameter estimates (density)

Validation Expectation

IFAD tends to yield parameter estimates with lower Monte Carlo variance compared to IF2 alone, so we expect to see that reflected in the narrower parameter density curves.


Comparison: Python vs R (pfilter check)

To verify the mathematical correctness of pypomp’s particle filter against R’s pomp, we compare their respective log-likelihood evaluations at a fixed, identical parameter set (specifically, the Maximum Likelihood Estimate (MLE) used as the default parameter set in pomp).

LogLik (density)

Validation Expectation

The log-likelihood estimate densities should overlap heavily.

LogLik Summary Statistics

Comparison of LogLik Statistics: Python vs R

Source N Mean Std Min Median Max
Python (pypomp) 3600 -3748.45 0.80 -3751.23 -3748.45 -3745.58
R (pomp) 3600 -3748.43 0.81 -3751.50 -3748.42 -3745.53