Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
b3486ca
Add regularize term function, and modified SSE to add option
sscini Mar 20, 2025
76ffb22
Fixed term in function
sscini Mar 20, 2025
50d6417
Merge branch 'main' into parmest_obj_regularization
sscini Mar 26, 2025
055f14c
Update parmest.py
sscini Apr 2, 2025
626c1b9
Revert "Update parmest.py"
sscini Apr 2, 2025
e853cc2
Reapply "Update parmest.py"
sscini Apr 2, 2025
77c2832
Add theta_ref and prior_FIM to keyword args
sscini Apr 2, 2025
cfe6460
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Apr 2, 2025
7d0c956
Adjust naming convention to ensure consistency.
sscini Apr 2, 2025
fae8500
Update parmest.py, DoE meeting work
sscini Apr 2, 2025
7b16637
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Jun 23, 2025
22d9031
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Jul 1, 2025
61d72c7
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Jul 7, 2025
8f36179
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Jul 8, 2025
2d2ec2d
Updated for next round of review
sscini Jul 15, 2025
d1ab692
Added regularization weight to exp class initialize
sscini Jul 15, 2025
bd212f4
Still debugging, progress as of 7/15/2025
sscini Jul 15, 2025
31bdf53
Merge branch 'main' into parmest_obj_regularization
sscini Jan 30, 2026
ec14208
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Feb 5, 2026
a3b4b4c
Update parmest.py
sscini Feb 6, 2026
7a0f623
Fixed issues with merging changes
sscini Feb 15, 2026
31a61e9
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Feb 15, 2026
d44f13d
L2 regularization working
sscini Feb 17, 2026
906f280
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Feb 17, 2026
fec94fd
Made the theta_ref a series.
sscini Feb 17, 2026
6ecb2a3
Updated doc strings.
sscini Feb 17, 2026
865e51e
Update parmest.py
sscini Feb 17, 2026
5ffa566
added helper comments.
sscini Feb 17, 2026
53ca679
Updated implementation to add vectorized L2 calc, and reviewer questions
sscini Feb 19, 2026
ab583bb
Adjusted logging, ran black
sscini Feb 19, 2026
ac96277
Changed value to avoid zero for L2 term
sscini Feb 19, 2026
08bce8f
Commented out or removed print statements
sscini Feb 19, 2026
26bc6b6
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Feb 19, 2026
7aa3b17
Merge branch 'main' into parmest_obj_regularization
sscini Feb 23, 2026
ec60888
Chose to apply in compute_covariance
sscini Mar 2, 2026
9531d73
Update parmest.py
sscini Mar 2, 2026
bc79da5
Made weight default 1
sscini Mar 2, 2026
0456910
Ran black
sscini Mar 2, 2026
23eb2ea
Adjusted doc strings, ran black
sscini Mar 2, 2026
933da0f
Update regularization_example.py
sscini Mar 2, 2026
ec100ae
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Mar 6, 2026
e20e457
Added validation for prior_FIM and fixed inconsistencies
sscini Mar 6, 2026
850819c
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Mar 6, 2026
baadbf0
Added L1 reg support working prototype, black
sscini Mar 9, 2026
351920f
Fixed testing issue, and example issues
sscini Mar 9, 2026
a0decd0
Merge branch 'main' into parmest_obj_regularization
sscini Mar 17, 2026
a7d1fb8
Merge branch 'main' into parmest_obj_regularization
sscini Mar 24, 2026
9786fc5
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Mar 27, 2026
6d46119
Added tests to correct files, ran black.
sscini Mar 29, 2026
14bc329
Updated model structure, reordered, ran black
sscini Apr 2, 2026
f84786c
Merge branch 'Pyomo:main' into parmest_obj_regularization
sscini Apr 7, 2026
a123706
Merge branch 'main' into parmest_obj_regularization
sscini Apr 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# ____________________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2026 National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and Engineering
# Solutions of Sandia, LLC, the U.S. Government retains certain rights in this
# software. This software is distributed under the 3-clause BSD License.
# ____________________________________________________________________________________

from pyomo.common.dependencies import pandas as pd
import pyomo.contrib.parmest.parmest as parmest
from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import (
RooneyBieglerExperiment,
)


def main():
"""
Compare L2 and smooth-L1 regularization on the Rooney-Biegler example.

Notes
-----
The model response saturates for large positive ``rate_constant`` values:
``y = asymptote * (1 - exp(-rate_constant * hour))``.
If ``rate_constant`` is both unpenalized and unbounded, the objective can be
nearly flat in that direction, which can lead to extreme fitted values.
To keep the smooth-L1 fit numerically stable and interpretable, this example:
1) includes a nonzero L1 weight on ``rate_constant`` via ``prior_FIM_l1``, and
2) applies finite bounds ``rate_constant in [0, 5]`` on each experiment model.
"""

# Rooney & Biegler Reference Values
# a = 19.14, b = 0.53
theta_ref = pd.Series({'asymptote': 20.0, 'rate_constant': 0.8})

# L2 setup: create a 'Stiff' Prior for 'asymptote' but leave 'rate_constant' flexible.
prior_FIM_l2 = pd.DataFrame(
[[1000.0, 0.0], [0.0, 0.0]],
index=['asymptote', 'rate_constant'],
columns=['asymptote', 'rate_constant'],
)
# L1 setup: penalize both parameters to avoid an unregularized flat direction.
prior_FIM_l1 = pd.DataFrame(
[[1000.0, 0.0], [0.0, 1.0]],
index=['asymptote', 'rate_constant'],
columns=['asymptote', 'rate_constant'],
)

# Data
data = pd.DataFrame(
data=[[1, 8.3], [2, 10.3], [3, 19.0], [4, 16.0], [5, 15.6], [7, 19.8]],
columns=['hour', 'y'],
)

# Create an experiment list
exp_list = []
for i in range(data.shape[0]):
exp = RooneyBieglerExperiment(data.loc[i, :])
# Example-scoped stabilization: keep rate_constant in a practical range.
m = exp.get_labeled_model()
m.rate_constant.setlb(0.0)
m.rate_constant.setub(5.0)
exp_list.append(exp)

# Create an instance of the parmest estimator (L2)
pest_l2 = parmest.Estimator(
exp_list,
obj_function="SSE",
regularization='L2',
prior_FIM=prior_FIM_l2,
theta_ref=theta_ref,
)

# Parameter estimation and covariance for L2
obj_l2, theta_l2 = pest_l2.theta_est()
cov_l2 = pest_l2.cov_est()

# L1 smooth regularization uses sqrt((theta - theta_ref)^2 + epsilon)
pest_l1 = parmest.Estimator(
exp_list,
obj_function="SSE",
regularization='L1',
prior_FIM=prior_FIM_l1,
theta_ref=theta_ref,
regularization_weight=1.0,
regularization_epsilon=1e-6,
)
obj_l1, theta_l1 = pest_l1.theta_est()
cov_l1 = pest_l1.cov_est()

if parmest.graphics.seaborn_available:
parmest.graphics.pairwise_plot(
(theta_l2, cov_l2, 100),
theta_star=theta_l2,
alpha=0.8,
distributions=['MVN'],
title='L2 regularized theta estimates within 80% confidence region',
)

# Assert statements compare parameter estimation (theta) to an expected value
# relative_error = abs(theta['asymptote'] - 19.1426) / 19.1426
# assert relative_error < 0.01
# relative_error = abs(theta['rate_constant'] - 0.5311) / 0.5311
# assert relative_error < 0.01

return {"L2": (obj_l2, theta_l2, cov_l2), "L1": (obj_l1, theta_l1, cov_l1)}


if __name__ == "__main__":
results = main()
for reg_name, (obj, theta, cov) in results.items():
print(f"{reg_name} estimated parameters (theta):", theta)
print(f"{reg_name} objective function value at theta:", obj)
print(f"{reg_name} covariance of parameter estimates:", cov)
Loading
Loading