CasADi - 最优控制开源 Python/MATLAB 库4

本文涉及的产品
NLP自然语言处理_基础版,每接口每天50万次
NLP 自学习平台,3个模型定制额度 1个月
NLP自然语言处理_高级版,每接口累计50万次
简介: CasADi - 最优控制开源 Python/MATLAB 库

CasADi - 最优控制开源 Python/MATLAB 库3:https://developer.aliyun.com/article/1584026

6.3. 导入外部函数

CasADi 外部函数的基本用法已在第 5.2 节的自动生成代码中进行了演示。同样的函数也可用于导入用户定义的函数,只要该函数也使用第 5.3 节所述的 C API。

下文将对此进行进一步阐述。

6.3.1. 默认函数

通常无需定义第 5.3 节中定义的所有函数。如果没有定义 fname_incref 和 fname_decref,则假定不需要内存管理。如果没有提供输入和输出的名称,它们将被赋予默认名称。一般情况下,稀疏性模式默认为标量模式,除非函数对应于另一个函数的导数(见下文),在这种情况下,稀疏性模式默认为密集模式且维度正确。

此外,如果没有实现 fname_work,则假定不需要工作矢量。

6.3.2. 作为注释的元信息

如果您依赖于 CasADi 的即时编译器,您可以在 C 代码中以注释的形式提供元信息,而不是实现实际的回调函数。

元信息的结构如下:

/*CASADIMETA
:fname_N_IN 1
:fname_N_OUT 2
:fname_NAME_IN[0] x
:fname_NAME_OUT[0] r
:fname_NAME_OUT[1] s
:fname_SPARSITY_IN[0] 2 1 0 2
*/


6.3.3. 导数

外部函数可以通过提供导数计算函数来实现微分。在导数计算过程中,CasADi 将在同一文件/共享库中寻找符合特定命名规则的符号。例如,您可以通过执行名为 jac_fname 的函数,为名为 fname 的函数指定相对于所有输入的所有输出的雅各比。同样,您可以通过提供名为 fwd1_fname 的函数来指定计算一个正向导数的函数,其中 1 可以用 2、4、8、16、32 或 64 代替,以便一次计算多个正向导数。对于反向模式方向导数,可将 fwd 替换为 adj。


这是一项试验性功能。

6.4. 即时编译 C 语言字符串

在上一节中,我们介绍了如何指定一个包含数值计算函数和元信息的 C 语言文件。如前所述,CasADi 与 Clang 的接口可以对该文件进行即时编译。用户只需将源代码指定为一个 C 语言字符串即可。

body =\
'r[0] = x[0];'+\
'while (r[0]<s[0]) {'+\
' r[0] *= r[0];'+\
'}'

f = Function.jit('f',body,\
      ['x','s'],['r'],\
      {"compiler":"shell"})
print(f)
f:(x,s)->(r) JitFunction

Function.jit 的这四个参数是必须的: 函数名称、字符串形式的 C 代码以及输入和输出名称。在 C 代码中,输入/输出名称对应于 casadi_real_t 类型的数组,其中包含函数输入和输出的非零元素。默认情况下,所有输入和输出都是标量(即 1-by-1 且密集)。要指定不同的稀疏性模式,请提供两个额外的函数参数,其中包含稀疏性模式的向量/列表:

sp = Sparsity.scalar()
f = Function.jit('f',body,\
     ['x','s'], ['r'],\
     [sp,sp], [sp],\
     {"compiler":"shell"})
print(f)
f:(x,s)->(r) JitFunction

两种变体都接受以选项字典形式出现的第 5 个(或第 7 个)可选参数。

6.5. 使用查找表

可以使用 CasADi 的插值函数创建查找表。不同的插值方案以插件形式实现,类似于 nlpsol 或 integrator 对象。除了标识符名称和插件外,插值函数还需要一组网格点和相应的数值。


内插函数调用的结果是一个可微分的 CasADi 函数对象,可以通过调用 MX 参数嵌入到 CasADi 计算图形中。此外,此类图形完全支持 C 代码生成。


目前,插值法有两个插件: 线性 "和 “bspline”。它们的作用类似于 MATLAB/Octave 的插值,方法设置为 "线性 "或 “样条”–对应于多线性插值和非结边界条件下的样条插值(默认为立方)。


在使用 bspline 的情况下,将在构建时寻找符合所提供数据的系数。或者,您也可以使用更低级的 Function.bspline 来自行提供系数。默认情况下,bspline 的每个维度的阶数都是 3。您可以通过阶数选项偏离默认值。


我们将介绍一维和二维版本的插值法语法,但实际上该语法可用于任意维数。

6.5.1. 一维查找表

与 SciPy 中的相应方法相比,CasADi/Python 中的一维样条曲线拟合方法如下:

import casadi as ca
import numpy as np
xgrid = np.linspace(1,6,6)
V = [-1,-1,-2,-3,0,2]
lut = ca.interpolant('LUT','bspline',[xgrid],V)
print(lut(2.5))
# Using SciPy
import scipy.interpolate as ip
interp = ip.InterpolatedUnivariateSpline(xgrid, V)
print(interp(2.5))
-1.35
-1.3500000000000005

在 MATLAB/Octave 中,相应的代码为

xgrid = 1:6;
V = [-1 -1 -2 -3 0 2];
lut = casadi.interpolant('LUT','bspline',{xgrid},V);
lut(2.5)
% Using MATLAB/Octave builtin
interp1(xgrid,V,2.5,'spline')
ans =

-1.35

ans = -1.3500

请特别注意,内插法的网格和数值参数必须是数值参数。

6.5.2. 二维查找表

在 Python 中,我们可以得到以下二维查找表,也可以与 SciPy 进行比较,以供参考:

xgrid = np.linspace(-5,5,11)
ygrid = np.linspace(-4,4,9)
X,Y = np.meshgrid(xgrid,ygrid,indexing='ij')
R = np.sqrt(5*X**2 + Y**2)+ 1
data = np.sin(R)/R
data_flat = data.ravel(order='F')
lut = ca.interpolant('name','bspline',[xgrid,ygrid],data_flat)
print(lut([0.5,1]))
# Using Scipy

interp = ip.RectBivariateSpline(xgrid, ygrid, data)
print(interp.ev(0.5,1))
0.245507
0.24550661674668917

或在 MATLAB/Octave 中与内置函数进行比较:

xgrid = -5:1:5;
ygrid = -4:1:4;
[X,Y] = ndgrid(xgrid, ygrid);
R = sqrt(5*X.^2 + Y.^2)+ 1;
V = sin(R)./R;
lut = interpolant('LUT','bspline',{xgrid, ygrid},V(:));
lut([0.5 1])
% Using Matlab builtin
interpn(X,Y,V,0.5,1,'spline')
ans =

0.245507

ans = 0.2455

特别要注意的是,values 参数必须扁平化为一维数组。

6.6. 使用有限差分进行衍生计算

CasADi 3.3 为所有函数对象引入了有限差分计算支持,特别是包括第 6.2 节、第 6.3 节或第 6.4 节中定义的外部函数(对于第 6.5 节中的查找表,可使用解析导数)。

除 Function.jit 外,有限差分导数默认为禁用,要启用有限差分导数,必须将 "enable_fd "选项设置为 True/true:

f = external('f', './gen.so',\
   dict(enable_fd=True))

e = jacobian(f(x),x)
D = Function('d',[x],[e])
print(D(0))
1

参见第 5.1 节。


如果没有分析导数,"enable_fd "选项可以让 CasADi 使用有限差分。要强制 CasADi 使用有限差分,可以将 “enable_fd”、"enable_reverse "和 "enable_jacobian "设置为 “假”/“假”,分别对应于 CasADi 所使用的三种分析导数信息。


默认方法是中心差法,步长由函数的舍入误差和截断误差估算值决定。您可以通过将 "fd_method "选项设置为 “forward”(对应一阶正向差分)、“backward”(对应一阶反向差分)和 “smoothing”(二阶精确非连续性避免方案)来更改方法,适用于需要计算域边缘导数的情况。通过设置 "fd_options "选项,可以获得有限差分的其他算法选项。

七、 DaeBuilder 类

CasADi 中的 DaeBuilder 类是一个辅助类,旨在方便复杂动力系统的建模,以便日后与最优控制算法配合使用。该类的抽象层级低于物理建模语言,如 Modelica(参见第 7.2 节),但仍高于直接使用 CasADi 符号表达式的层级。特别是,它可以用来连接以功能模拟接口(FMI)格式提供的物理模型,也可以用作构建特定领域建模环境的构件。


DaeBuilder 原则上有三种不同的使用方法:

可以使用该类逐步构建微分代数方程(DAE)结构系统,然后将其用于连接 CasADi 中的仿真或优化。该类还支持以 FMI 格式导出模型,以便在其他工具中使用。


还可以使用该类导入 FMI 格式的现有模型。从 CasADi 3.6 开始,我们支持导入标准 FMU,其中的模型方程只能通过调用 DLL 来获得。FMU 导入支持已针对具有挑战性的 FMU 进行了测试,但截至本文撰写时仍在开发中。


我们可以使用该类以 XML 符号格式导入现有模型。JModelica.org 工具支持这种格式,OpenModelica 也试验性地支持这种格式。由于生成这种格式的模型的工具有限,因此这种格式没有得到积极的开发。

7.1. 构建 DaeBuilder 实例

下面是一个简单的 DAE,它对应于一个受二次空气摩擦项和重力作用的可控火箭,火箭在耗尽燃料后质量会逐渐减小:

image.png


其中,三种状态分别对应高度、速度和质量。

是火箭的推力,(a、 b ) 为参数。

要构建该问题的 DAE 公式,请从一个空的 DaeBuilder 实例开始,按如下步骤逐步添加输入和输出表达式。

dae = DaeBuilder('rocket')
# Add input expressions
a = dae.add_p('a')
b = dae.add_p('b')
u = dae.add_u('u')
h = dae.add_x('h')
v = dae.add_x('v')
m = dae.add_x('m')
# Add output expressions
hdot = v
vdot = (u-a*v**2)/m-g
mdot = -b*u**2
dae.set_ode('h', hdot)
dae.set_ode('v', vdot)
dae.set_ode('m', mdot)
# Specify initial conditions
dae.set_start('h', 0)
dae.set_start('v', 0)
dae.set_start('m', 1)
# Add meta information
dae.set_unit('h','m')
dae.set_unit('v','m/s')
dae.set_unit('m','kg')

其他输入和输出表达式也可以类似方式添加。有关函数的完整列表,请参见 DaeBuilder 的 C++ API 文档。

7.2. 从 Modelica 符号导入 OCP*

注:Modelon 不再提供 JModelica.org。但其闭源后继代码 OCT 保留了 CasADi 的互操作性。关于如何使用 OCT 生成 CasADi 表达式的详细信息,请参阅 OCT 的用户指南。以下文字指的是传统的 Modelica 互操作性支持。

7.2.1. 从 XML 文件的传统符号导入

除了直接在 CasADi 中建模(如上所述),还有一种方法是使用高级物理建模语言(如 Modelica)来指定模型。为此,CasADi 提供了与开源 JModelica.org 编译器的互操作性,该编译器是专门为优化控制而编写的。从 JModelica.org 导入模型有两种不同的方式:使用 JModelica.org 的 CasadiInterface 或通过 DaeBuilder 的 parse_fmi 命令。


我们推荐使用前一种方法,因为它正在得到积极维护,有关如何提取 CasADi 表达式的详细信息,请参阅 JModelica.org 的用户指南。


下面,我们将概述使用 parse_fmi 的传统方法。

7.2.2. 从传统方法导入 modelDescription.xml 文件¶。

要了解如何使用 Modelica 导入,请查看 CasADi 示例集中的 thermodynamics_example.py。


假设 Modelica/Optimica 模型 ModelicaClass.ModelicaModel 定义在 file1.mo 和 file2.mop 文件中,Python 编译命令为


from pymodelica import compile_jmu
jmu_name=compile_jmu('ModelicaClass.ModelicaModel', \
  ['file1.mo','file2.mop'],'auto','ipopt',\
  {'generate_xml_equations':True, 'generate_fmi_me_xml':False})

这将生成一个 jmu 文件,实质上是一个压缩文件,其中包含 modelDescription.xml 文件。该 XML 文件包含最优控制问题的符号表示,可在标准 XML 编辑器中查看。

from zipfile import ZipFile
sfile = ZipFile(jmu_name','r')
mfile = sfile.extract('modelDescription.xml','.')

一旦有了 modelDescription.xml 文件,就可以使用 parse_fmi 命令将其导入:

 ocp = DaeBuilder()
ocp.parse_fmi('modelDescription.xml')

7.3. 函数工厂

一旦一个 DaeBuilder 被提出,并可能被重新表述为一个令人满意的形式,我们就可以生成与 sec-daebuilder_io 中列出的输入和输出表达式相对应的 CasADi 函数。例如,要为第 7.1 节中的火箭模型的 ODE 右侧创建一个函数,只需提供所创建函数的显示名称、输入表达式列表和输出表达式列表:

f = dae.create('f',\
     ['x','u','p'],['ode'])

利用命名规则,我们还可以创建雅各布函数,例如 "ode "输出相对于 "x "的雅各布函数:

f = dae.create('f',\
     ['x','u','p'],\
     ['jac_ode_x'])

首先使用 add_lc 创建输出表达式的命名线性组合,然后请求其 Hessian,即可提取具有二阶信息的函数:

dae.add_lc('gamma',['ode'])
hes = dae.create('hes',\
  ['x','u','p','lam_ode'],\
  ['hes_gamma_x_x'])

也可以简单地从 DaeBuilder 实例中提取符号表达式,然后手动创建 CasADi 函数。例如,dae.x 包含与 "x "相对应的所有表达式,dae.ode 包含与 "ode "相对应的表达式,等等。


脚注


[1]

FMI 开发小组。Functional Mock-up Interface for Model Exchange and Co-Simulation. https://www.fmi-standard.org/, July 2014. 规范,FMI 2.0。第 3.1 节,第 71-72 页。

八、使用 CasADi 进行优化控制

CasADi 可用于使用多种方法解决最优控制问题(OCP),包括直接(又称离散化-优化)和间接(又称优化-离散化)方法、一次求解(如搭配)方法以及需要嵌入 ODE 或 DAE 初值求解器的射击方法。作为用户,通常需要编写自己的 OCP 求解器,而 CasADi 的目标是通过提供功能强大的高级构建模块,尽可能简化这一过程。由于是自己编写求解器(而不是调用现有的 "黑盒 "求解器),因此对如何求解 OCP 的基本了解是必不可少的。Biegler [1] 或 Betts 最近出版的教科书对数值最优控制做了很好的、自成一体的介绍。

[1] 或 Betts

[2] 或 Moritz Diehl 的数值最优控制讲义。

8.1. 一个简单的测试问题

为了说明某些方法,我们将考虑以下测试问题,即驱动一个范德尔波尔振荡器到原点,同时试图最小化二次费用:

image.png

8.1.1. 直接单射法

在直接单次射击法中,控制轨迹使用某种片断平滑近似值(通常是片断常数)进行参数化。

使用控制的显式表达,我们就可以从优化问题中消除整个状态轨迹,最终只对离散化的控制进行 NLP。

在 CasADi 的示例集中,您可以找到分别用于 Python 和 MATLAB/Octave 的 direct_single_shooting.py 和 direct_single_shooting.m 代码。这些代码实现了直接单次射击法,并使用 IPOPT 进行求解,依靠 CasADi 计算导数。为了从连续时间动力学获得离散时间动力学,使用 CasADi 符号实现了一个简单的固定步 Runge-Kutta 4 (RK4) 积分器。类似这样的简单积分器代码在优化控制中通常很有用,但必须注意准确解决初值问题。


该代码还展示了如何用一种更先进的积分器(即 SUNDIALS 软件包中的 CVODES 积分器)取代 RK4 方案,后者实现了一种可变步长、可变阶次的后向微分公式 (BDF) 方案。这种高级积分器适用于较大系统、具有刚性动力学的系统、DAEs 以及检查较简单方案的一致性。

8.1.2. 直接多重射击

在 CasADi 示例集中的 direct_multiple_shooting.py 和 direct_multiple_shooting.m 代码实现了直接多重射击法。这种方法与直接单次射击法非常相似,但将某些射击节点的状态作为 NLP 中的决策变量,并包含相等约束以确保轨迹的连续性。


由于将问题 "提升 "到一个更高的维度通常会提高收敛性,因此直接多重射击法通常优于直接单次射击法。用户还可以使用已知的状态轨迹猜测进行初始化。


缺点是所求解的 NLP 会变得更大,不过这通常会被更稀疏的事实所弥补。

8.1.3. 直接定位

最后,direct_collocation.py 和 direct_collocation.m 代码实现了直接搭配法。在这种情况下,整个状态轨迹的参数化(如片断低阶多项式)将作为 NLP 的决策变量。这样就完全不需要离散时间动力学公式了。

直接配准的 NLP 比直接多重射击的 NLP 更大,但也更稀疏。


脚注


[1]

Lorenz T. Biegler, Nonlinear Programming: Concepts, Algorithms, and Applications to Chemical Processes , SIAM 2010


[2]

John T. Betts, Practical Methods for Optimal Control Using Nonlinear Programming , SIAM 2001


[3]

您可以在 CasADi 的下载区以名为 examples_pack.zip 的压缩包形式获取此合集。

九、Opti 栈

Opti 栈是一组 CasADi 辅助类,提供了数学 NLP 符号之间的紧密对应关系,例如

image.png

opti = casadi.Opti()

x = opti.variable()
y = opti.variable()

opti.minimize(  (y-x**2)**2   )
opti.subject_to( x**2+y**2==1 )
opti.subject_to(       x+y>=1 )

opti.solver('ipopt')


sol = opti.solve()

print(sol.value(x))
print(sol.value(y))
0.7861513776531158
0.6180339888825889

Opti 栈的主要特点是

允许约束的自然语法。

隐藏决策变量的索引/簿记。

数字数据类型与宿主语言之间的映射更紧密:不会与 DM 发生冲突。

默认情况下,Opti 将假定程序为非线性程序。要求解二次方程式程序,请将字符串 "conic "作为 Opti 构造函数的参数。

9.1. 问题说明

变量 声明任意数量的决策变量:


x = opti.variable(): 标量


x = opti.variable(5):列向量


x = opti.variable(5,3):矩阵


x = opti.variable(5,5,‘symmetric’):对称矩阵


解算器会遵守变量声明的顺序。请注意,变量实际上是普通的 MX 符号。您可以对它们执行任何 CasADi MX 操作,例如嵌入积分器调用。


参数: 声明任意数量的参数。在求解之前必须将其固定为一个特定数值,并且可以随时覆盖该数值。

p = opti.parameter()
opti.set_value(p, 3)

目标: 使用可能涉及所有变量或参数的表达式声明目标。再次调用该命令将丢弃旧目标。

opti.minimize(   sin(x*(y-p))

约束 声明任意数量的相等/不相等约束:

opti.subject_to( sqrt(x+y) >= 1): 不等式

opti.subject_to( sqrt(x+y) > 1): 同上

opti.subject_to( 1<= sqrt(x+y) ): 同上

opti.subject_to( 5*x+y==1 ): 相等

您还可以同时抛出多个约束条件:

opti.subject_to([x*y>=1,x==3])

您可以声明双重不等式:

opti.subject_to( opti.bounded(0,x,1) )

当双不等式的边界不含变量时,约束条件将被有效地传递给支持它们的求解器(特别是 IPOPT)。

您可以使用向量进行元素(不)相等:

x = opti.variable(5,1)

opti.subject_to( x*p<=3 )

矩阵的元素(不)等式不支持自然语法,因为半定义性约束存在歧义。解决方法是先进行矢量化:

A = opti.variable(5,5)
opti.subject_to( vec(A)<=3 )

每条 subject_to 命令都会增加问题说明中的约束条件集。使用 subject_to() 命令可以清空约束条件集,然后重新开始。


求解器 必须始终声明求解器(数值后端)。第二个参数可以是一个可选的 CasADi 插件选项字典。第三个参数可以是求解器选项的可选字典。

p_opts = {"expand":True}
s_opts = {"max_iter": 100}
opti.solver("ipopt",p_opts,
                    s_opts)

初始猜测:您可以提供决策变量(或决策变量的简单映射)的初始猜测。如果没有提供初始值,则假定数值为零。

opti.set_initial(x, 2)
opti.set_initial(10*x[0], 2)

9.2. 解决问题和检索

9.2.1. 求解

设置问题后,您可以调用求解方法,该方法会构造一个 CasADi nlpsol 并调用它。

sol = opti.solve()
This is Ipopt version 3.14.11, running with linear solver MUMPS 5.4.1.

Number of nonzeros in equality constraint Jacobian...:        2
Number of nonzeros in inequality constraint Jacobian.:        2
Number of nonzeros in Lagrangian Hessian.............:        3

Total number of variables............................:        2
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:        1
Total number of inequality constraints...............:        1
        inequality constraints with only lower bounds:        1
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        0

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  0.0000000e+00 1.00e+00 1.00e+00  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1  1.5180703e+00 2.32e-01 3.95e+08  -1.0 1.11e+00    -  9.90e-01 1.00e+00h  1
   2  9.1720733e-01 1.38e-02 8.65e+08  -1.0 1.05e-01  10.0 1.00e+00 1.00e+00f  1
   3  8.9187743e-01 4.67e-05 9.29e+06  -1.0 7.19e-03    -  1.00e+00 1.00e+00h  1
   4  8.9179090e-01 5.46e-10 2.17e+02  -1.0 2.42e-05    -  1.00e+00 1.00e+00h  1
   5  8.5961118e-01 2.43e-04 3.39e+00  -1.0 1.56e-02    -  1.00e+00 1.00e+00f  1
   6  5.0768568e-01 3.58e-02 2.18e+00  -1.0 1.89e-01    -  3.86e-01 1.00e+00f  1
   7  4.4751644e-01 4.12e-04 6.30e+07  -1.0 1.96e-02   9.5 1.00e+00 1.00e+00h  1
   8  4.4707538e-01 4.25e-08 2.27e+04  -1.0 2.53e-04    -  1.00e+00 1.00e+00h  1
   9  4.4688522e-01 9.34e-09 2.20e+00  -1.0 9.32e-05    -  1.00e+00 1.00e+00h  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  10  2.9995484e-02 3.46e-01 1.19e+00  -1.0 5.68e-01    -  5.45e-01 1.00e+00f  1
  11  3.9964883e-04 3.56e-02 5.81e-02  -1.0 2.09e-01    -  1.00e+00 1.00e+00h  1
  12  3.7581923e-06 5.63e-04 5.70e-03  -2.5 2.69e-02    -  1.00e+00 1.00e+00h  1
  13  7.6573980e-10 1.48e-06 3.13e-05  -3.8 1.11e-03    -  1.00e+00 1.00e+00h  1
  14  4.8778322e-14 2.53e-10 7.52e-09  -5.7 1.29e-05    -  1.00e+00 1.00e+00h  1
  15  8.8029044e-20 1.60e-14 6.47e-13  -8.6 9.88e-08    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 15

                                   (scaled)                 (unscaled)
Objective...............:   8.8029044107981477e-20    8.8029044107981477e-20
Dual infeasibility......:   6.4749359014643689e-13    6.4749359014643689e-13
Constraint violation....:   1.5987211554602254e-14    1.5987211554602254e-14
Variable bound violation:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   2.5060006300485104e-09    2.5060006300485104e-09
Overall NLP error.......:   2.5060006300485104e-09    2.5060006300485104e-09


Number of objective function evaluations             = 16
Number of objective gradient evaluations             = 16
Number of equality constraint evaluations            = 16
Number of inequality constraint evaluations          = 16
Number of equality constraint Jacobian evaluations   = 16
Number of inequality constraint Jacobian evaluations = 16
Number of Lagrangian Hessian evaluations             = 15
Total seconds in IPOPT                               = 0.009

EXIT: Optimal Solution Found.
      solver  :   t_proc      (avg)   t_wall      (avg)    n_eval
       nlp_f  | 125.00us (  7.81us)  30.37us (  1.90us)        16
       nlp_g  | 254.00us ( 15.88us)  61.01us (  3.81us)        16
  nlp_grad_f  | 161.00us (  9.47us)  40.36us (  2.37us)        17
  nlp_hess_l  | 237.00us ( 15.80us)  57.98us (  3.87us)        15
   nlp_jac_g  | 218.00us ( 12.82us)  55.16us (  3.24us)        17
       total  |  39.25ms ( 39.25ms)   9.88ms (  9.88ms)         1

如果求解器收敛失败,调用将失败并提示错误。你仍然可以检查未收敛的解法(参见第 9.3 节)。

您可以多次调用求解。您将始终获得一份不可更改的问题规范及其解决方案。连续调用求解无助于问题的收敛。

要热启动求解器,需要明确地将一个问题的解转移到下一个问题的初始值中。

sol1 = opti.solve()
print(sol1.stats()["iter_count"])

# Solving again makes no difference
sol1 = opti.solve()
print(sol1.stats()["iter_count"])

# Passing initial makes a difference
opti.set_initial(sol1.value_variables())
sol2 = opti.solve()
print(sol2.stats()["iter_count"])
15
15
4
sol1 = opti.solve();
sol1.stats.iter_count

% Solving again makes no difference
sol1 = opti.solve();
sol1.stats.iter_count

% Passing initial makes a difference
opti.set_initial(sol1.value_variables());
sol2 = opti.solve();
sol2.stats.iter_count
ans = 15
ans = 15
ans = 4

为了初始化对偶变量,例如在求解一组相似的优化问题时,可以使用以下语法:

sol = opti.solve()
lam_g0 = sol.value(opti.lam_g)
opti.set_initial(opti.lam_g, lam_g0)
sol = opti.solve();
lam_g0 = sol.value(opti.lam_g);
opti.set_initial(opti.lam_g, lam_g0);

9.2.2. 求解时的数值

之后,您可以获取变量(或变量的表达式)在解时的数值:

sol.value(x):决策变量的数值

sol.value§:参数值

sol.value(sin(x+p)):表达式的值

sol.value(jacobian(opti.g,opti.x)):约束条件 jacobian 的值

请注意,在适用情况下,值的返回类型是稀疏的。

9.2.3. 其他点的数值

您可以向 value 传递一系列推翻赋值表达式。在下面的代码中,我们要求得到目标值,并使用解决方案中的所有最优值,但 y 除外,我们将其设置为 2。请注意,此语句不会永久修改 y 的实际最优值。`

obj = (y-x**2)**2

opti.minimize(obj)


print(sol.value(obj,[y==2]))
1.909830056703819
obj = (y-x^2)^2;

opti.minimize(obj);



sol.value(obj,{y==2})
ans = 1.9098

一个相关的使用模式是在初始猜测时对表达式进行评估:

print(sol.value(x**2+y,opti.initial()))
0.0
sol.value(x**2+y,opti.initial())
ans = 0

9.2.4. 对偶变量

为了获得约束条件的对偶变量(拉格朗日乘数),请确保先保存约束条件表达式:

con = sin(x+y)>=1
opti.subject_to(con)
sol = opti.solve()

print(sol.value(opti.dual(con)))
0.258679501736367
con = sin(x+y)>=1;
opti.subject_to(con);
sol = opti.solve();

sol.value(opti.dual(con))
ans = 0.2587

9.3. 额外内容

求解器很可能找不到最优解。在这种情况下,您仍然可以通过调试模式访问未求和的解:

opti.debug.value(x)

与此相关的是,你还可以根据提供给求解器的初始猜测,查看表达式的值:

opti.debug.value(x,opti.initial())

如果求解器因问题不可行而停止,您可以使用

opti.debug.show_infeasibilities()

如果求解器在某个位置报告了 NaN/Inf,您可以通过查看其描述找出是哪个约束或变量的问题:

opti.debug.x_describe(index)
opti.debug.g_describe(index)

您可以指定一个回调函数;求解器每次迭代时都会调用该函数,参数为当前迭代次数。要绘制求解器的进度图,可以通过调试模式访问未求和的解决方案:

opti.callback(lambda i: plot(opti.debug.value(x)))
opti.callback(@(i) plot(opti.debug.value(x)))

可以通过调用不带参数的回调函数,从 Opti 堆栈中清除回调。

您可以通过调用 to_function 函数,从 Opti 对象中构造一个普通的 CasADi 函数。所提供的输入参数列表可能包含参数、决策变量和双重变量。与变量相对应的输入将作为初始猜测。如果希望在求解失败时抛出运行时错误,可以通过 error_on_fail 作为求解器选项。

f = opti.to_function("f",[x,y],[x**2+y])
print(f(0, 0))
1.23607
f = opti.to_function('f',{x,y},{x^2+y});
disp(f(0, 0))
1.23607

十、 不同语言的用法差异* 10.1.

10.1. 一般用法

例句:

10.2. 操作列表

以下是最重要的操作列表。不同语言中的不同操作用星号 (*) 标出。该列表并不完整,也未显示每个操作的所有变体。更多信息请参阅 API 文档。

目录
相关文章
|
6天前
|
机器学习/深度学习 PyTorch 算法框架/工具
python这些库和框架哪个更好
【9月更文挑战第2天】python这些库和框架哪个更好
18 6
|
6天前
|
机器学习/深度学习 数据采集 算法框架/工具
python有哪些常用的库和框架
【9月更文挑战第2天】python有哪些常用的库和框架
14 6
|
10天前
|
数据采集 XML Web App开发
6个强大且流行的Python爬虫库,强烈推荐!
6个强大且流行的Python爬虫库,强烈推荐!
WK
|
6天前
|
数据采集 XML 安全
常用的Python网络爬虫库有哪些?
Python网络爬虫库种类丰富,各具特色。`requests` 和 `urllib` 简化了 HTTP 请求,`urllib3` 提供了线程安全的连接池,`httplib2` 则具备全面的客户端接口。异步库 `aiohttp` 可大幅提升数据抓取效率。
WK
21 1
WK
|
9天前
|
机器学习/深度学习 数据采集 算法框架/工具
Python那些公认好用的库
Python拥有丰富的库,适用于数据科学、机器学习、网络爬虫及Web开发等领域。例如,NumPy和Pandas用于数据处理,Matplotlib和Dash用于数据可视化,Scikit-learn、TensorFlow和PyTorch则助力机器学习。此外,Pillow和OpenCV专长于图像处理,Pydub处理音频,Scrapy和Beautiful Soup则擅长网络爬虫工作
WK
18 4
|
10天前
|
机器学习/深度学习 JSON 数据挖掘
什么是 Python 库?
【8月更文挑战第29天】
32 4
|
9天前
|
机器学习/深度学习 存储 算法
NumPy 与 SciPy:Python 科学计算库的比较
【8月更文挑战第30天】
31 1
|
10天前
|
开发框架 Java 数据管理
我使用Python开发网站的3个主要框架库,强烈推荐
我使用Python开发网站的3个主要框架库,强烈推荐
|
9天前
|
机器学习/深度学习 数据可视化 数据挖掘
Python中的数据可视化:使用Matplotlib库绘制图表
【8月更文挑战第30天】数据可视化是数据科学和分析的关键组成部分,它帮助我们以直观的方式理解数据。在Python中,Matplotlib是一个广泛使用的绘图库,提供了丰富的功能来创建各种类型的图表。本文将介绍如何使用Matplotlib库进行数据可视化,包括安装、基本概念、绘制不同类型的图表以及自定义图表样式。我们将通过实际代码示例来演示如何应用这些知识,使读者能够轻松地在自己的项目中实现数据可视化。
|
10天前
|
数据采集 程序员 测试技术
比 requests 更强大 Python 库,让你的爬虫效率提高一倍!
比 requests 更强大 Python 库,让你的爬虫效率提高一倍!
下一篇
DDNS