Nic*_*nar 6 c c++ matlab mathematical-optimization numerical-methods
我想知道是否有一个C/C++库或Matlab代码技术来使用最小化求解器来确定实数和复数.这是一个代码片段,显示了我想要做的事情.例如,假设我知道Utilde,但不是x和U变量.我想使用optimization(fminsearch)来确定x和U给定Utilde.请注意,这Utilde是一个复数.
x = 1.5;
U = 50 + 1i*25;
x0 = [1 20]; % starting values
Utilde = U * (1 / exp(2 * x)) * exp( 1i * 2 * x);
xout = fminsearch(@(v)optim(v, Utilde), x0);
function diff = optim(v, Utilde)
x = v(1);
U = v(2);
diff = abs( -(Utilde/U) + (1 / exp(2 * x)) * exp( 1i * 2 * x ) );
Run Code Online (Sandbox Code Playgroud)
上面的代码没有收敛到正确的值,并且xout = 1.7318 88.8760.但是,如果 U = 50,这不是一个复数,那么xout = 1.5000 50.0000,这是正确的值.
在Matlab或C/C++中是否有一种方法可以确保适当的收敛,Utilde以复数形式给出?也许我必须更改上面的代码?
如果没有办法在Matlab中本地执行此操作,那么问题的一个要点可能是:是否存在能够处理实际和复杂输入的多变量(即Nelder-Mead或类似算法)优化库输出?
另一个问题是函数是否收敛.我不知道它是算法还是函数.我可能需要更改Utilde = U * (1 / exp(2 * x)) * exp( 1i * 2 * x)表达式中的某些内容以使其收敛吗?
这里的主要问题是这个优化或参数拟合问题没有唯一的解决方案。例如,查看上面的预期结果和实际结果,对于两个 ( , )Utilde对来说是等效的(忽略舍入差异),即xU
Utilde(x = 1.5, U = 50 + 25i) = Utilde(x = 1.7318, U = 88.8760)
Run Code Online (Sandbox Code Playgroud)
尽管我没有深入研究它,但我什至怀疑对于 的任何值x,您都可以找到U计算为 的Utilde(x, U) = Utilde(x = 1.5, U = 50 + 25i)。
因此,这里的解决方案是进一步约束参数拟合问题,以便求解器产生任何可以被认为可接受的解决方案。或者,重新公式化以使任何 ( , )Utilde对具有唯一值。xU
8 月 1 日更新
给定合理的起始值,实际上似乎限制x为实值就足够了。使用上面公式化的函数执行无约束非线性优化diff,我得到以下结果:
x = 1.50462926953244
U = 50.6977768845879 + 24.7676554234729i
diff = 3.18731710515855E-06
Run Code Online (Sandbox Code Playgroud)
然而,将起始猜测更改为距期望值更远的值确实会产生不同的解决方案,因此限制x为实值并不能单独为问题提供唯一的解决方案。
我已经使用BOBYQA优化器在 C# 中实现了这一点,但数字应该与上面相同。如果您想在 Matlab 之外尝试,使用std::complex类和您自己选择的(不受约束的)非线性 C++ 优化器将下面的 C# 代码转换为 C++ 代码也应该相对简单。您可以在这里找到一些不需要梯度计算的 C++ 兼容代码,并且 Numerical Recipes 中也提供了各种实现。例如,您可以在此处在线访问 NR 的 C 版本。
作为参考,以下是我的 C# 代码的相关部分:
class Program
{
private static readonly Complex Coeff = new Complex(-2.0, 2.0);
private static readonly Complex UTilde0 = GetUTilde(1.5, new Complex(50.0, 25.0));
static void Main(string[] args)
{
double[] vars = new[] {1.0, 25.0, 0.0}; // xstart = 1.0, Ustart = 25.0
BobyqaExitStatus status = Bobyqa.FindMinimum(GetObjfnValue, vars.Length, vars);
}
public static Complex GetUTilde(double x, Complex U)
{
return U * Complex.Exp(Coeff * x);
}
public static double GetObjfnValue(int n, double[] vars)
{
double x = vars[0];
Complex U = new Complex(vars[1], vars[2]);
return Complex.Abs(-UTilde0 / U + Complex.Exp(Coeff * x));
}
}
Run Code Online (Sandbox Code Playgroud)