我想知道是否存在使用最小化求解器确定实数和复数的C/C++库或Matlab代码技术。这是一个代码片段,显示了我想做什么。例如,假设我知道Utilde,但不知道xU变量。我想使用优化(fminsearch)来确定xU(给定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  ) );

上面的代码未收敛到正确的值xout = 1.7318 88.8760。但是,如果U = 50不是复数,则xout = 1.5000 50.0000是适当的值。

给定Utilde为复数,在Matlab或C/C++中有没有一种方法可以确保适当的收敛?也许我必须更改上面的代码?
  • 如果在Matlab中没有 native 执行此操作的方法,那么也许
    问题的要点是:是否存在多元变量(即
    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)
    

    尽管我没有对其进行深入研究,但我什至怀疑对于x的任何值,您都可以找到计算为UUtilde(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
    

    但是,将起始猜测值更改为更远离期望值的值确实会产生不同的解决方案,因此将x限制为实值并不能单独提供问题的唯一解决方案。

    我已经使用BOBYQA优化器在C#中实现了此功能,但是数字应该与上面的相同。如果您想在Matlab之外尝试,使用std::complex类和您自己选择的(无约束)非线性C++优化器将下面的C#代码转换为C++代码也应该相对简单。您可能会发现一些不需要梯度计算的C++兼容代码here,并且在数值食谱中也有多种实现方式。例如,您可以访问NR在线here的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));
        }
    }
    

    09-17 20:10