Note
Go to the end to download the full example code.
Create a first-order Taylor polynomial#
The TaylorDiscipline can be used
to evaluate the first-order polynomial of a discipline
defined at a specific input point.
It can be useful for studies
requiring a lot of evaluations of a discipline,
which is time-consuming but fairly linear around this point.
from __future__ import annotations
from numpy import array
from gemseo.disciplines.analytic import AnalyticDiscipline
from gemseo.disciplines.taylor import TaylorDiscipline
Let us consider a discipline computing \(y\) from \(x=(x_1,x_2)\) using the function
discipline = AnalyticDiscipline(
{"y1": "sin(x1)+cos(x2)", "y2": "cos(x1)+sin(x2)"}, name="f"
)
In the following, we seek to approximate this model using the first-order Taylor polynomial of \(f\) at an input point \(a\):
which could be implemented by hand as follows:
expected_taylor_discipline = AnalyticDiscipline(
{
"y1": "sin(a1)+cos(a2)+cos(a1)*(x1-a1)-sin(a2)*(x2-a2)",
"y2": "cos(a1)+sin(a2)-sin(a1)*(x1-a1)+cos(a2)*(x2-a2)",
},
name="expected_f_a",
)
Taylor at default input data#
For that,
we can instantiate the TaylorDiscipline from the previous discipline,
using the discipline.input_data as the value of \(a\):
taylor_discipline = TaylorDiscipline(discipline, name="f_a")
We can execute it with its default input data \(a\):
taylor_discipline.execute()
{'x1': array([0.]), 'x2': array([0.]), 'y1': array([1.]), 'y2': array([1.])}
and compare the results with the expected first-order Taylor polynomial:
expected_taylor_discipline.execute()
print(taylor_discipline.get_output_data(), expected_taylor_discipline.get_output_data())
{'y1': array([1.]), 'y2': array([1.])} {'y1': array([1.]), 'y2': array([1.])}
We can also execute it with custom input data and compare the results with the expected first-order Taylor polynomial:
taylor_discipline.execute({"x1": array([0.2]), "x2": array([-0.8])})
expected_taylor_discipline.execute({"x1": array([0.2]), "x2": array([-0.8])})
taylor_discipline.get_output_data(), expected_taylor_discipline.get_output_data()
({'y1': array([1.2]), 'y2': array([0.2])}, {'y1': array([1.2]), 'y2': array([0.2])})
Taylor at custom input data#
We can also use a custom value of \(a\), e.g. \((0.2, -0.8)\) (and compare the results):
taylor_discipline = TaylorDiscipline(
discipline, name="f_a", input_data={"x1": array([0.2]), "x2": array([-0.8])}
)
execute taylor_discipline with its default input data \(a\):
taylor_discipline.execute()
{'x1': array([0.2]), 'x2': array([-0.8]), 'y1': array([0.89537604]), 'y2': array([0.26271049])}
and compare the results with the expected first-order Taylor polynomial:
expected_taylor_discipline.default_input_data["a1"] = array([0.2])
expected_taylor_discipline.default_input_data["a2"] = array([-0.8])
expected_taylor_discipline.execute({"x1": array([0.2]), "x2": array([-0.8])})
taylor_discipline.get_output_data(), expected_taylor_discipline.get_output_data()
({'y1': array([0.89537604]), 'y2': array([0.26271049])}, {'y1': array([0.89537604]), 'y2': array([0.26271049])})
We can also execute it with custom input data
taylor_discipline.execute({"x1": array([1.2]), "x2": array([0.7])})
{'x1': array([1.2]), 'x2': array([0.7]), 'y1': array([2.95147675]), 'y2': array([1.10910122])}
and compare the results with the expected first-order Taylor polynomial:
expected_taylor_discipline.execute({"x1": array([1.2]), "x2": array([0.7])})
taylor_discipline.get_output_data(), expected_taylor_discipline.get_output_data()
({'y1': array([2.95147675]), 'y2': array([1.10910122])}, {'y1': array([2.95147675]), 'y2': array([1.10910122])})
Note
When the discipline is almost linear over the input range of interest
and provides the analytical derivatives,
a TaylorDiscipline can be a very relevant surrogate model.
Indeed,
it can be built with only 1 evaluation
whereas a simple linear model would need \(1+d\) evaluations
where \(d\) is the dimension of the input space.
Total running time of the script: (0 minutes 0.043 seconds)