From 3685dc0cc861f3bb3b7ca54cf0978388e37ab37c Mon Sep 17 00:00:00 2001 From: Peter Stahlecker Date: Thu, 31 Oct 2024 05:58:51 +0100 Subject: [PATCH 1/5] problem 10.7 of Betts' book --- .../example_10_7_betts_test_problems.py | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 examples-gallery/example_10_7_betts_test_problems.py diff --git a/examples-gallery/example_10_7_betts_test_problems.py b/examples-gallery/example_10_7_betts_test_problems.py new file mode 100644 index 00000000..19aac858 --- /dev/null +++ b/examples-gallery/example_10_7_betts_test_problems.py @@ -0,0 +1,123 @@ +""" +Hypersensitive Control +====================== + +This is example 10.7 from Betts' Test Problems, in the book: +"Practical Methods for Optimal Control Using Nonlinear Programming", 3rd edition, +Chapter 10, by John T. Betts. + +**States** + +- y : state variable +- uy: its speed + +**Specifieds** + +- u : control variable + +Note: the state variable uy is needed because opt currently needs minimum two +differential equations in the equations of motion. Mathematically it is not +needed. + +""" + +import numpy as np +import sympy as sm +import sympy.physics.mechanics as me +from opty.direct_collocation import Problem +from opty.utils import create_objective_function +import matplotlib.pyplot as plt + +# %% +# Equations of motion. + +t = me.dynamicsymbols._t +y, uy, u = me.dynamicsymbols('y uy, u') + +eom = sm.Matrix([ uy - y.diff(t), -uy - y**3 + u]) +sm.pprint(eom) + +# %% +# I packed the optimization problem and its solution into a function, so that +# I can easily call it with different parameters. + +def solve_optimization(nodes, tf): + t0, tf = 0.0, tf + num_nodes = nodes + interval_value = (tf - t0)/(num_nodes - 1) + + # Provide some reasonably realistic values for the constants. + + state_symbols = (y, uy) + specified_symbols = (u,) + + + # Specify the objective function and form the gradient. + obj_func = sm.Integral(y**2 + u**2, t) + sm.pprint(obj_func) + obj, obj_grad = create_objective_function(obj_func, + state_symbols, + specified_symbols, + tuple(), + num_nodes, + node_time_interval=interval_value) + + + # Specify the symbolic instance constraints, as per the example + instance_constraints = ( + y.func(t0) - 1, + y.func(tf) - 1.5, + ) + + + # Create the optimization problem and set any options. + prob = Problem(obj, obj_grad, eom, state_symbols, + num_nodes, interval_value, + instance_constraints=instance_constraints, + ) + + prob.add_option('nlp_scaling_method', 'gradient-based') + + # Give some rough estimates for the trajectories. + initial_guess = np.zeros(prob.num_free) + + # Find the optimal solution. + solution, info = prob.solve(initial_guess) + print(info['status_msg']) + print(f'Objective value achieved: {info['obj_val']:.4f}, as per the book ' + + f'it is {6.7241}, so the error is: ' + f'{(info['obj_val'] - 6.7241)/6.7241*100:.3f} % ') + + # Plot the optimal state and input trajectories. + prob.plot_trajectories(solution) + + # Plot the constraint violations. + prob.plot_constraint_violations(solution) + + # Plot the objective function as a function of optimizer iteration. + prob.plot_objective_value() + +# %% +# As per the example tf = 10000 + +tf = 10000 +num_nodes = 501 +solve_optimization(num_nodes, tf) + +# %% +# With the value of tf = 10000 above, opty converged to a locally optimal point, +# but the objective value is far from the one given in the book. +# As per the plot of the solution y(t) it seems, that most of the time y(t) = 0, +# only at the very beginning and the very end it is different from 0. +# So, it may make sense to use a smaller tf. +# Also increasing num_nodes may help. + +tf = 8.0 +num_nodes = 10001 +solve_optimization(num_nodes, tf) + +# %% + +# sphinx_gallery_thumbnail_number = 4 + +plt.show() From 873c46a5c5da121da59094d928dfaf1585201b51 Mon Sep 17 00:00:00 2001 From: Peter Stahlecker Date: Thu, 31 Oct 2024 12:21:32 +0100 Subject: [PATCH 2/5] corrected name of file --- .../plot_example_10_7_betts_test_problems.py | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 examples-gallery/plot_example_10_7_betts_test_problems.py diff --git a/examples-gallery/plot_example_10_7_betts_test_problems.py b/examples-gallery/plot_example_10_7_betts_test_problems.py new file mode 100644 index 00000000..2436194b --- /dev/null +++ b/examples-gallery/plot_example_10_7_betts_test_problems.py @@ -0,0 +1,143 @@ +""" +Hypersensitive Control +====================== + +This is example 10.7 from Betts' Test Problems, in the book: +"Practical Methods for Optimal Control Using Nonlinear Programming", 3rd edition, +Chapter 10, by John T. Betts. + +**States** + +- y : state variable +- uy: its speed + +**Specifieds** + +- u : control variable + +Note: the state variable uy is needed because opt currently needs minimum two +differential equations in the equations of motion. Mathematically it is not +needed. + +""" + +import numpy as np +import sympy as sm +import sympy.physics.mechanics as me +from opty.direct_collocation import Problem +from opty.utils import create_objective_function +import matplotlib.pyplot as plt + +# %% +# Equations of motion. + +t = me.dynamicsymbols._t +y, uy, u = me.dynamicsymbols('y uy, u') + +eom = sm.Matrix([ uy - y.diff(t), -uy - y**3 + u]) +sm.pprint(eom) + +# %% +# I packed the optimization problem and its solution into a function, so that +# I can easily call it with different parameters. + +def solve_optimization(nodes, tf): + t0, tf = 0.0, tf + num_nodes = nodes + interval_value = (tf - t0)/(num_nodes - 1) + + # Provide some reasonably realistic values for the constants. + + state_symbols = (y, uy) + specified_symbols = (u,) + + + # Specify the objective function and form the gradient. + obj_func = sm.Integral(y**2 + u**2, t) + sm.pprint(obj_func) + obj, obj_grad = create_objective_function(obj_func, + state_symbols, + specified_symbols, + tuple(), + num_nodes, + node_time_interval=interval_value) + + + # Specify the symbolic instance constraints, as per the example + instance_constraints = ( + y.func(t0) - 1, + y.func(tf) - 1.5, + ) + + + # Create the optimization problem and set any options. + prob = Problem(obj, obj_grad, eom, state_symbols, + num_nodes, interval_value, + instance_constraints=instance_constraints, + ) + + prob.add_option('nlp_scaling_method', 'gradient-based') + + # Give some rough estimates for the trajectories. + initial_guess = np.zeros(prob.num_free) + + # Find the optimal solution. + solution, info = prob.solve(initial_guess) + return solution, info, prob + +# %% +# As per the example tf = 10000 + +tf = 10000 +num_nodes = 501 +solution, info, prob = solve_optimization(num_nodes, tf) +print(info['status_msg']) +print(f'Objective value achieved: {info['obj_val']:.4f}, as per the book ' + + f'it is {6.7241}, so the error is: ' + f'{(info['obj_val'] - 6.7241)/6.7241*100:.3f} % ') + +# %% +# Plot the optimal state and input trajectories. +prob.plot_trajectories(solution) + +# %% +# Plot the constraint violations. +prob.plot_constraint_violations(solution) + +# %% +# Plot the objective function as a function of optimizer iteration. +prob.plot_objective_value() + + + +# %% +# With the value of tf = 10000 above, opty converged to a locally optimal point, +# but the objective value is far from the one given in the book. +# As per the plot of the solution y(t) it seems, that most of the time y(t) = 0, +# only at the very beginning and the very end it is different from 0. +# So, it may make sense to use a smaller tf. +# Also increasing num_nodes may help. + +tf = 8.0 +num_nodes = 10001 +solution, info, prob = solve_optimization(num_nodes, tf) +print(info['status_msg']) +print(f'Objective value achieved: {info['obj_val']:.4f}, as per the book ' + + f'it is {6.7241}, so the error is: ' + f'{(info['obj_val'] - 6.7241)/6.7241*100:.3f} % ') + +# %% +# Plot the optimal state and input trajectories. +prob.plot_trajectories(solution) + +# %% +# Plot the constraint violations. +prob.plot_constraint_violations(solution) + +# %% +# Plot the objective function as a function of optimizer iteration. +prob.plot_objective_value() + +# %% + +# sphinx_gallery_thumbnail_number = 4 From 72ea29b339211e6c92b8d0225b764b2e57054c7a Mon Sep 17 00:00:00 2001 From: Peter Stahlecker Date: Tue, 5 Nov 2024 17:13:24 +0100 Subject: [PATCH 3/5] examples 10.103 and 10.104 of Betts' book --- examples-gallery/plot_betts_10_103_104.py | 274 ++++++++++++++++++ ...ts_test_problems.py => plot_betts_10_7.py} | 0 2 files changed, 274 insertions(+) create mode 100644 examples-gallery/plot_betts_10_103_104.py rename examples-gallery/{plot_example_10_7_betts_test_problems.py => plot_betts_10_7.py} (100%) diff --git a/examples-gallery/plot_betts_10_103_104.py b/examples-gallery/plot_betts_10_103_104.py new file mode 100644 index 00000000..06202e2d --- /dev/null +++ b/examples-gallery/plot_betts_10_103_104.py @@ -0,0 +1,274 @@ +""" +Pendulum Problem: DAE vs. ODE Formulation +========================================= + +Pendulum Problem **DAE** Formulation + +This is example 10.103 from Betts' Test Problems. +It has four differential equations and one algebraic equation. + +Right below is eample 10.104 from Betts' Test Problems. Only difference is that +the algebraic equation has been differentiated w.r.t time t. + +As expected, the DAE formulation gives a better result than the ODE formulation. +The ODE formulation seems to run a bit faster. + + +**States** + +- :math:`y_0, ...y_4` : state variables + +**Specifieds** + +- :math:`u` : control variable + +""" + +import numpy as np +import sympy as sm +import sympy.physics.mechanics as me +from opty.direct_collocation import Problem +from opty.utils import create_objective_function +import time + +# %% +# Equations of motion. +t = me.dynamicsymbols._t +y = me.dynamicsymbols('y0 y1 y2 y3 y4') +u = me.dynamicsymbols('u') + +# Parameters +g = 9.81 + +eom = sm.Matrix([ + -y[0].diff(t) + y[2], + -y[1].diff(t) + y[3], + -y[2].diff(t) -2*y[4]*y[0] + u*y[1], + -y[3].diff(t) -g -2*y[4]*y[1] - u*y[0], + y[2]**2 + y[3]**2 - 2*y[4] - g*y[1] +]) +sm.pprint(eom) + +# %% +# Set up and solve the optimization problem. +# Parameters +tf = 3.0 +num_nodes = 751 + +t0, tf = 0.0, tf +interval_value = (tf - t0)/(num_nodes - 1) + +state_symbols = y +specified_symbols = (u,) + +# %% +# Specify the objective function and form the gradient. +start = time.time() +obj_func = sm.Integral(u**2, t) +sm.pprint(obj_func) +obj, obj_grad = create_objective_function(obj_func, + state_symbols, + specified_symbols, + tuple(), + num_nodes, + node_time_interval=interval_value, +) + +# %% +# Specify the symbolic instance constraints, as per the example +instance_constraints = ( + y[0].func(t0) - 1, + *[y[i].func(t0) - 0 for i in range(1, 5)], + y[0].func(tf) - 0, + y[2].func(tf) - 0, +) + +# %% +# bounds +bounds = { + y[0]: (-5, 5), + y[1]: (-5, 5), + y[2]: (-5, 5), + y[3]: (-5, 5), + y[4]: (-1, 15), +} + +# %% +# Create the optimization problem and set any options. +prob = Problem( + obj, + obj_grad, + eom, + state_symbols, + num_nodes, interval_value, + instance_constraints=instance_constraints, + bounds=bounds, +) + +prob.add_option('nlp_scaling_method', 'gradient-based') + +# Give some rough estimates for the x and y trajectories. +initial_guess = np.zeros(prob.num_free) + +# Find the optimal solution. +solution, info = prob.solve(initial_guess) +print(info['status_msg']) +if info['obj_val'] < 12.8738850: + msg = 'so, opty with DAE gets a better result' +else: + msg = 'opty with DAE gets a worse result' +print(f'Minimal objective value achieved: {info['obj_val']:.4f}, ' + + f'as per the book it is {12.8738850}, {msg} ') +time_DAE = time.time() - start +print(f'Time taken for the simulation: {time_DAE:.2f} s') + +obj_DAE = info['obj_val'] + +# %% +# Plot the optimal state and input trajectories. +prob.plot_trajectories(solution) + +# %% +# Plot the constraint violations. +prob.plot_constraint_violations(solution) + +# %% +# Plot the objective function as a function of optimizer iteration. +prob.plot_objective_value() + + +# %% +# +# Pendulum Problem **ODE** Formulation +# +# This is example 10.104 from Betts' Test Problems. +# +# **States** +# +# - :math:`y_0, ...y_4` : state variables +# +# **Specifieds** +# +#- :math:`u` : control variable + +# %% +# Equations of motion. +t = me.dynamicsymbols._t +y = me.dynamicsymbols('y0 y1 y2 y3 y4') +u = me.dynamicsymbols('u') + +# Parameters +g = 9.81 + +eom = sm.Matrix([ + -y[0].diff(t) + y[2], + -y[1].diff(t) + y[3], + -y[2].diff(t) -2*y[4]*y[0] + u*y[1], + -y[3].diff(t) -g -2*y[4]*y[1] - u*y[0], + -y[4].diff(t) + y[2]*y[2].diff(t) + y[3]*y[3].diff(t) - g*y[1].diff(t)/2.0, +]) +sm.pprint(eom) + +# %% +# Set up and solve the optimization problem. + +state_symbols = y +specified_symbols = (u,) + +# %% +# Specify the objective function and form the gradient. +start = time.time() +obj_func = sm.Integral(u**2, t) +sm.pprint(obj_func) +obj, obj_grad = create_objective_function(obj_func, + state_symbols, + specified_symbols, + tuple(), + num_nodes, + node_time_interval=interval_value, +) + +# %% +# Specify the symbolic instance constraints, as per the example +instance_constraints = ( + y[0].func(t0) - 1, + *[y[i].func(t0) for i in range(1, 5)], + y[0].func(tf) - 0, + y[2].func(tf) - 0, +) + +# bounds +bounds = { + y[0]: (-5, 5), + y[1]: (-5, 5), + y[2]: (-5, 5), + y[3]: (-5, 5), + y[4]: (-1, 15), +} + +# %% +# Create the optimization problem and set any options. +prob = Problem( + obj, + obj_grad, + eom, + state_symbols, + num_nodes, interval_value, + instance_constraints=instance_constraints, + bounds=bounds, +) + +prob.add_option('nlp_scaling_method', 'gradient-based') + +# Give some rough estimates for the x and y trajectories. +initial_guess = np.zeros(prob.num_free) + +# %% +# Find the optimal solution. +solution, info = prob.solve(initial_guess) +print(info['status_msg']) +if info['obj_val'] < 12.8738850: + msg = 'so, opty with ODE gets a better result' +else: + msg = 'opty with ODE gets a worse result' +print(f'Minimal objective value achieved: {info['obj_val']:.4f}, ' + + f'as per the book it is {12.8738850}, {msg} ') +time_ODE = time.time() - start +print(f'Time taken for the simulation: {time_ODE:.2f} s') + + +obj_ODE = info['obj_val'] + +# %% +# Plot the optimal state and input trajectories. +prob.plot_trajectories(solution) + +# %% +# Plot the constraint violations. +prob.plot_constraint_violations(solution) + +# %% +# Plot the objective function as a function of optimizer iteration. +prob.plot_objective_value() + +# %% +# Compare the results +#-------------------- + +if obj_DAE < obj_ODE: + value = (obj_ODE - obj_DAE)/obj_ODE*100 + print(f'DAE formulation gives a better result by {value:.2f} %') +else: + value = (obj_DAE - obj_ODE)/obj_DAE*100 + print(f'ODE formulation gives a better result by {value:.2f} %') + +if time_DAE < time_ODE: + value = (time_ODE - time_DAE)/time_ODE*100 + print(f'DAE formulation is faster by {value:.2f} %') +else: + value = (time_DAE - time_ODE)/time_DAE*100 + print(f'ODE formulation is faster by {value:.2f} %') + +# %% +# sphinx_gallery_thumbnail_number = 2 + diff --git a/examples-gallery/plot_example_10_7_betts_test_problems.py b/examples-gallery/plot_betts_10_7.py similarity index 100% rename from examples-gallery/plot_example_10_7_betts_test_problems.py rename to examples-gallery/plot_betts_10_7.py From 814c2d841feabb9002bbe199332860c60840b8dc Mon Sep 17 00:00:00 2001 From: Peter Stahlecker <83544146+Peter230655@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:24:09 +0100 Subject: [PATCH 4/5] Delete examples-gallery/example_10_7_betts_test_problems.py --- .../example_10_7_betts_test_problems.py | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 examples-gallery/example_10_7_betts_test_problems.py diff --git a/examples-gallery/example_10_7_betts_test_problems.py b/examples-gallery/example_10_7_betts_test_problems.py deleted file mode 100644 index 19aac858..00000000 --- a/examples-gallery/example_10_7_betts_test_problems.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -Hypersensitive Control -====================== - -This is example 10.7 from Betts' Test Problems, in the book: -"Practical Methods for Optimal Control Using Nonlinear Programming", 3rd edition, -Chapter 10, by John T. Betts. - -**States** - -- y : state variable -- uy: its speed - -**Specifieds** - -- u : control variable - -Note: the state variable uy is needed because opt currently needs minimum two -differential equations in the equations of motion. Mathematically it is not -needed. - -""" - -import numpy as np -import sympy as sm -import sympy.physics.mechanics as me -from opty.direct_collocation import Problem -from opty.utils import create_objective_function -import matplotlib.pyplot as plt - -# %% -# Equations of motion. - -t = me.dynamicsymbols._t -y, uy, u = me.dynamicsymbols('y uy, u') - -eom = sm.Matrix([ uy - y.diff(t), -uy - y**3 + u]) -sm.pprint(eom) - -# %% -# I packed the optimization problem and its solution into a function, so that -# I can easily call it with different parameters. - -def solve_optimization(nodes, tf): - t0, tf = 0.0, tf - num_nodes = nodes - interval_value = (tf - t0)/(num_nodes - 1) - - # Provide some reasonably realistic values for the constants. - - state_symbols = (y, uy) - specified_symbols = (u,) - - - # Specify the objective function and form the gradient. - obj_func = sm.Integral(y**2 + u**2, t) - sm.pprint(obj_func) - obj, obj_grad = create_objective_function(obj_func, - state_symbols, - specified_symbols, - tuple(), - num_nodes, - node_time_interval=interval_value) - - - # Specify the symbolic instance constraints, as per the example - instance_constraints = ( - y.func(t0) - 1, - y.func(tf) - 1.5, - ) - - - # Create the optimization problem and set any options. - prob = Problem(obj, obj_grad, eom, state_symbols, - num_nodes, interval_value, - instance_constraints=instance_constraints, - ) - - prob.add_option('nlp_scaling_method', 'gradient-based') - - # Give some rough estimates for the trajectories. - initial_guess = np.zeros(prob.num_free) - - # Find the optimal solution. - solution, info = prob.solve(initial_guess) - print(info['status_msg']) - print(f'Objective value achieved: {info['obj_val']:.4f}, as per the book ' + - f'it is {6.7241}, so the error is: ' - f'{(info['obj_val'] - 6.7241)/6.7241*100:.3f} % ') - - # Plot the optimal state and input trajectories. - prob.plot_trajectories(solution) - - # Plot the constraint violations. - prob.plot_constraint_violations(solution) - - # Plot the objective function as a function of optimizer iteration. - prob.plot_objective_value() - -# %% -# As per the example tf = 10000 - -tf = 10000 -num_nodes = 501 -solve_optimization(num_nodes, tf) - -# %% -# With the value of tf = 10000 above, opty converged to a locally optimal point, -# but the objective value is far from the one given in the book. -# As per the plot of the solution y(t) it seems, that most of the time y(t) = 0, -# only at the very beginning and the very end it is different from 0. -# So, it may make sense to use a smaller tf. -# Also increasing num_nodes may help. - -tf = 8.0 -num_nodes = 10001 -solve_optimization(num_nodes, tf) - -# %% - -# sphinx_gallery_thumbnail_number = 4 - -plt.show() From 8442e38b547eb035f8f6a7d8bd94c35b618cfe12 Mon Sep 17 00:00:00 2001 From: Peter Stahlecker <83544146+Peter230655@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:24:31 +0100 Subject: [PATCH 5/5] Delete examples-gallery/plot_betts_10_7.py --- examples-gallery/plot_betts_10_7.py | 143 ---------------------------- 1 file changed, 143 deletions(-) delete mode 100644 examples-gallery/plot_betts_10_7.py diff --git a/examples-gallery/plot_betts_10_7.py b/examples-gallery/plot_betts_10_7.py deleted file mode 100644 index 2436194b..00000000 --- a/examples-gallery/plot_betts_10_7.py +++ /dev/null @@ -1,143 +0,0 @@ -""" -Hypersensitive Control -====================== - -This is example 10.7 from Betts' Test Problems, in the book: -"Practical Methods for Optimal Control Using Nonlinear Programming", 3rd edition, -Chapter 10, by John T. Betts. - -**States** - -- y : state variable -- uy: its speed - -**Specifieds** - -- u : control variable - -Note: the state variable uy is needed because opt currently needs minimum two -differential equations in the equations of motion. Mathematically it is not -needed. - -""" - -import numpy as np -import sympy as sm -import sympy.physics.mechanics as me -from opty.direct_collocation import Problem -from opty.utils import create_objective_function -import matplotlib.pyplot as plt - -# %% -# Equations of motion. - -t = me.dynamicsymbols._t -y, uy, u = me.dynamicsymbols('y uy, u') - -eom = sm.Matrix([ uy - y.diff(t), -uy - y**3 + u]) -sm.pprint(eom) - -# %% -# I packed the optimization problem and its solution into a function, so that -# I can easily call it with different parameters. - -def solve_optimization(nodes, tf): - t0, tf = 0.0, tf - num_nodes = nodes - interval_value = (tf - t0)/(num_nodes - 1) - - # Provide some reasonably realistic values for the constants. - - state_symbols = (y, uy) - specified_symbols = (u,) - - - # Specify the objective function and form the gradient. - obj_func = sm.Integral(y**2 + u**2, t) - sm.pprint(obj_func) - obj, obj_grad = create_objective_function(obj_func, - state_symbols, - specified_symbols, - tuple(), - num_nodes, - node_time_interval=interval_value) - - - # Specify the symbolic instance constraints, as per the example - instance_constraints = ( - y.func(t0) - 1, - y.func(tf) - 1.5, - ) - - - # Create the optimization problem and set any options. - prob = Problem(obj, obj_grad, eom, state_symbols, - num_nodes, interval_value, - instance_constraints=instance_constraints, - ) - - prob.add_option('nlp_scaling_method', 'gradient-based') - - # Give some rough estimates for the trajectories. - initial_guess = np.zeros(prob.num_free) - - # Find the optimal solution. - solution, info = prob.solve(initial_guess) - return solution, info, prob - -# %% -# As per the example tf = 10000 - -tf = 10000 -num_nodes = 501 -solution, info, prob = solve_optimization(num_nodes, tf) -print(info['status_msg']) -print(f'Objective value achieved: {info['obj_val']:.4f}, as per the book ' + - f'it is {6.7241}, so the error is: ' - f'{(info['obj_val'] - 6.7241)/6.7241*100:.3f} % ') - -# %% -# Plot the optimal state and input trajectories. -prob.plot_trajectories(solution) - -# %% -# Plot the constraint violations. -prob.plot_constraint_violations(solution) - -# %% -# Plot the objective function as a function of optimizer iteration. -prob.plot_objective_value() - - - -# %% -# With the value of tf = 10000 above, opty converged to a locally optimal point, -# but the objective value is far from the one given in the book. -# As per the plot of the solution y(t) it seems, that most of the time y(t) = 0, -# only at the very beginning and the very end it is different from 0. -# So, it may make sense to use a smaller tf. -# Also increasing num_nodes may help. - -tf = 8.0 -num_nodes = 10001 -solution, info, prob = solve_optimization(num_nodes, tf) -print(info['status_msg']) -print(f'Objective value achieved: {info['obj_val']:.4f}, as per the book ' + - f'it is {6.7241}, so the error is: ' - f'{(info['obj_val'] - 6.7241)/6.7241*100:.3f} % ') - -# %% -# Plot the optimal state and input trajectories. -prob.plot_trajectories(solution) - -# %% -# Plot the constraint violations. -prob.plot_constraint_violations(solution) - -# %% -# Plot the objective function as a function of optimizer iteration. -prob.plot_objective_value() - -# %% - -# sphinx_gallery_thumbnail_number = 4