Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5c72266
Implementation of `ParametrisedReducedFunctional` as a subclass of `R…
divijghose Feb 4, 2026
69b4f42
Add `ParametrisedReducedFunctional` to `__init__`
divijghose Feb 4, 2026
afb45b7
Implementation of `ParametrisedReducedFunctional` as a subclass of th…
divijghose Feb 13, 2026
931655c
Implementation of `ParametrisedReducedFunctional` which calls `Reduce…
divijghose Feb 13, 2026
f290791
Update pyadjoint/reduced_functional.py
divijghose Feb 13, 2026
fb93ec4
Remove `derivative_components` as a kwarg to `ReducedFunctional`
divijghose Feb 13, 2026
af191c8
Updated `all_controls` to work if a list of parameters is passed. Eac…
divijghose Feb 13, 2026
bfd0d3e
Tests for Parametrised Reduced Functional:
divijghose Feb 16, 2026
ce926dc
Added a test to compare `ParametrisedReducedFunctional` against `Redu…
divijghose Feb 16, 2026
24ead4f
Change `parameter_update` to `update_parameters`
divijghose Feb 20, 2026
b983316
Update pyadjoint/reduced_functional.py
divijghose Feb 20, 2026
fab260b
Update pyadjoint/reduced_functional.py
divijghose Feb 20, 2026
11b384d
Updated `optimize_tape`
divijghose Feb 20, 2026
a426418
Updated `parameters` to return a list of `OverloadedType`
divijghose Feb 20, 2026
ff38909
Update pyadjoint/reduced_functional.py
divijghose Feb 20, 2026
e4dc322
Correct typo in test name
divijghose Feb 20, 2026
9dcfc64
Update `ParametrisedReducedFunctional` to raise an error if an empty …
divijghose Feb 20, 2026
7ac3220
Removed redundant check for parameters being instance of `Control`. T…
divijghose Feb 20, 2026
3d5a619
Changes to the test for Parametrised RF (`test_parametrised_rf`:
divijghose Feb 27, 2026
c960fec
Added a mathematical description to the parametrised reduced function…
divijghose Feb 27, 2026
6c07824
Update tests to include a minimzation problem with a quadratic polyno…
divijghose Mar 6, 2026
7147a6c
Import `ParametrisedReducedFunctional` in `optimization.py` and assig…
divijghose Mar 17, 2026
c9eddc6
Create a `ParametrisedReducedFunctionalNumpy` class for downstream use.
divijghose Mar 17, 2026
94d3548
Added a test to check for optimisation with a quadratic polynomial us…
divijghose Mar 23, 2026
6bdc6f7
Remove code duplication for `ParametrisedReducedFunctionalNumPy`. The…
divijghose Mar 23, 2026
876942e
Change in `derivative` (and associated tests) to not return a list of…
divijghose Mar 23, 2026
15f2b48
Changes to `hessian` for parametrised RF:
divijghose Mar 23, 2026
91fad19
Changes to `tlm` for paremetrised RF:
divijghose Mar 23, 2026
c46b096
Separate out the callbacks for `controls` and `parameters` in paramet…
divijghose Mar 23, 2026
a342f53
Stricter tolerances for the TAO solver test
divijghose Mar 30, 2026
3530074
Empty commit to test CI
divijghose Apr 21, 2026
1a2bbd2
Update tests/pyadjoint/test_parametrised_rf.py
divijghose Apr 28, 2026
c71c040
Update pyadjoint/reduced_functional.py
divijghose Apr 28, 2026
1060efd
Update pyadjoint/reduced_functional.py
divijghose Apr 28, 2026
cd76d26
Fix tests: updated new `complicated_expression` function in the tests
divijghose Apr 28, 2026
5e45110
Fixed a test to avoid controls and parameters appearing on multiple t…
divijghose Apr 28, 2026
4790026
Fix test to be conditionally skipped if petsc4py is not installed
divijghose Apr 28, 2026
c075344
Update pyadjoint/reduced_functional.py
divijghose Apr 28, 2026
f9c93a9
Update pyadjoint/reduced_functional.py
divijghose Apr 28, 2026
035b60e
Update pyadjoint/reduced_functional.py
divijghose Apr 28, 2026
2f228fb
Remove `ParametrisedReducedFunctional` from `__init__`
divijghose Apr 30, 2026
007a8ac
Remove `ParametrisedReducedFunctional` from `optimization`
divijghose Apr 30, 2026
4f3e0e9
Changes to `reduced_functional.py`:
divijghose Apr 30, 2026
9545ae5
Removed `ParametrisedReducedFunctional` from tests, and added a new t…
divijghose Apr 30, 2026
bef36b8
Remove `ParametrisedReducedFunctional` from imports
divijghose Apr 30, 2026
762332f
Fixed taylor test to show more information if something fails
divijghose Apr 30, 2026
6f74a9f
Fix changes to callbacks that break downstream tests
divijghose May 4, 2026
47ef338
Linting
divijghose May 4, 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
3 changes: 2 additions & 1 deletion pyadjoint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .verification import taylor_test, taylor_to_dict
from .drivers import compute_gradient, compute_derivative, compute_tlm, compute_hessian, solve_adjoint
from .checkpointing import disk_checkpointing_callback
from .reduced_functional import ReducedFunctional
from .reduced_functional import ReducedFunctional, ParametrisedReducedFunctional
from .adjfloat import AdjFloat, exp, log
from .tape import (
Tape,
Expand Down Expand Up @@ -54,6 +54,7 @@
"log",
"Control",
"ReducedFunctional",
"ParametrisedReducedFunctional",
"create_overloaded_object",
"OverloadedType",
"compute_gradient",
Expand Down
138 changes: 138 additions & 0 deletions pyadjoint/reduced_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,141 @@ def marked_controls(self):
finally:
for control in self.controls:
control.unmark_as_control()

class ParametrisedReducedFunctional(AbstractReducedFunctional):
"""Class representing the reduced functional with parameters.

A reduced functional maps a control value to the provided functional.
It may also be used to compute the derivative of the functional with
respect to the control. In addition, parameters may be specified which
are updated, but not included in the derivative calculations.
Comment thread
divijghose marked this conversation as resolved.
Outdated

Args:
functional (:obj:`OverloadedType`): An instance of an OverloadedType,
usually :class:`AdjFloat`. This should be the return value of the
functional you want to reduce.
controls (list[Control]): A list of Control instances, which you want
to map to the functional. It is also possible to supply a single
Control instance instead of a list.
parameters (list): A list of parameters, which are updated, but not included in the derivative.
scale (float): A scaling factor applied to the functional and its
gradient with respect to the control.
tape (Tape): A tape object that the reduced functional will use to
evaluate the functional and its gradients (or derivatives).
eval_cb_pre (function): Callback function before evaluating the
functional. Input is a list of Controls.
eval_cb_pos (function): Callback function after evaluating the
Comment thread
divijghose marked this conversation as resolved.
Outdated
functional. Inputs are the functional value and a list of Controls.
derivative_cb_pre (function): Callback function before evaluating
derivatives. Input is a list of Controls.
Should return a list of Controls (usually the same
list as the input) to be passed to compute_derivative.
derivative_cb_post (function): Callback function after evaluating
derivatives. Inputs are: functional.block_variable.checkpoint,
list of functional derivatives, list of functional values.
Should return a list of derivatives (usually the same
list as the input) to be returned from self.derivative.
hessian_cb_pre (function): Callback function before evaluating the Hessian.
Input is a list of Controls.
hessian_cb_post (function): Callback function after evaluating the Hessian.
Inputs are the functional, a list of Hessian, and controls.
tlm_cb_pre (function): Callback function before evaluating the tangent linear model.
Input is a list of Controls.
tlm_cb_post (function): Callback function after evaluating the tangent linear model.
Inputs are the functional, the tlm result, and controls.
Comment thread
JHopeCollins marked this conversation as resolved.
Outdated
"""
def __init__(self, functional, controls, parameters,
scale=1.0, tape=None,
eval_cb_pre=lambda *args: None,
eval_cb_post=lambda *args: None,
derivative_cb_pre=lambda controls: controls,
derivative_cb_post=lambda checkpoint, derivative_components,
controls: derivative_components,
Comment thread
JHopeCollins marked this conversation as resolved.
Outdated
hessian_cb_pre=lambda *args: None,
hessian_cb_post=lambda *args: None,
tlm_cb_pre=lambda *args: None,
tlm_cb_post=lambda *args: None):
if not isinstance(functional, OverloadedType):
raise TypeError("Functional must be an OverloadedType.")
if parameters is None:
raise ValueError("Parameters must be provided. If no parameters are needed, use ReducedFunctional instead.")
Comment thread
divijghose marked this conversation as resolved.
Outdated
self._controls = Enlist(controls)
self._parameters = Enlist(parameters)
self.n_opt = len(self._controls)
self._all_controls= self._controls + Enlist([Control(p) if not isinstance(p, Control) else p for p in self._parameters])
Comment thread
JHopeCollins marked this conversation as resolved.
Outdated

self._reduced_functional = ReducedFunctional(functional=functional,
controls=self._all_controls,
scale=scale,
tape=tape,
eval_cb_pre=eval_cb_pre,
eval_cb_post=eval_cb_post,
derivative_cb_pre=derivative_cb_pre,
derivative_cb_post=derivative_cb_post,
hessian_cb_pre=hessian_cb_pre,
hessian_cb_post=hessian_cb_post,
tlm_cb_pre=tlm_cb_pre,
tlm_cb_post=tlm_cb_post)



@property
def controls(self) -> list[Control]:
return self._controls

@property
def parameters(self) -> list[Control]:
return self._parameters
Comment thread
divijghose marked this conversation as resolved.
Outdated

@no_annotations
def parameter_update(self, new_parameters):
Comment thread
divijghose marked this conversation as resolved.
Outdated
if len(Enlist(new_parameters)) != len(self._parameters):
raise ValueError(
"""new_parameters should be a list of the same
length as parameters."""
)
self._parameters = Enlist(new_parameters)

@no_annotations
def derivative(self, adj_input=1.0, apply_riesz=False):
derivatives_all = self._reduced_functional.derivative(adj_input=adj_input,
apply_riesz=apply_riesz)

return Enlist(derivatives_all)[:self.n_opt]
Comment thread
divijghose marked this conversation as resolved.
Outdated

@no_annotations
def __call__(self, values):
values = Enlist(values)
if len(values) != self.n_opt:
raise ValueError("Length of values passed to ParametrisedReducedFunctional" \
" must match the number of optimization controls.")
# concatenate optimization controls + parameters
full_values = values + self._parameters
return self._reduced_functional.__call__(full_values)
Comment thread
divijghose marked this conversation as resolved.
Outdated



Comment thread
divijghose marked this conversation as resolved.
Outdated

@no_annotations
def hessian(self, m_dot, hessian_input=None, evaluate_tlm=True, apply_riesz=False):
hessian_all = self._reduced_functional.hessian(m_dot,
hessian_input=hessian_input,
evaluate_tlm=evaluate_tlm,
apply_riesz=apply_riesz)
Comment thread
divijghose marked this conversation as resolved.
Outdated

return hessian_all[:self.n_opt] # Return only the hessian components corresponding to optimization controls.
Comment thread
divijghose marked this conversation as resolved.
Outdated


@no_annotations
def tlm(self, m_dot):
tlm_all = self._reduced_functional.tlm(m_dot)
return tlm_all[:self.n_opt] # Return only the tlm components corresponding to optimization controls.
Comment thread
divijghose marked this conversation as resolved.
Outdated


def optimize_tape(self):
self._reduced_functional.tape.optimize(
controls=self._reduced_functional.controls,
functionals=[self._reduced_functional.functional]
)
Comment thread
divijghose marked this conversation as resolved.
Outdated


Comment thread
divijghose marked this conversation as resolved.
Outdated
Loading