C语言中的广义约化梯度算法

4
我正在进行一些科学项目,需要使用C语言实现广义约化梯度算法来解决非线性优化问题。有没有相关库或者代码可以提供?如果没有,请建议其他非线性多变量问题的解决方案。我想使用四个独立变量和两个常数构建一个非线性优化模型。
我已经使用Microsoft Excel的求解器,使用广义约化梯度(GRG)算法完美地解决了这个模型,但是我需要在C语言中为我的模拟实现这个算法。
以下是我的Excel解决方案: http://speedy.sh/SEdZj/eof-cs-rest.xlsm 我使用Microsoft Excel Solver和GRG算法搜索SS的最小值,并输出Const_a和Const_b的值。

Mathlab还是Wolfram?这是我脑海中首先想到的东西。你也可以在Math Overflow上提问。 - Michael Dorgan
这是基于一组常微分方程的非线性模型吗?在这里,“常数”和“独立变量”的区别是什么? - s.bandara
@JonathanGrynspan 我已经尝试了Excel中的求解器,它运行良好。现在我需要在C中实现类似的功能。 - darko_5
@MichaelDorgan Matlab、Mathematica和Excel对于这种问题非常好,但我需要用C语言实现一个解决方案。 - darko_5
@s.bandara,这类似于f(x1,x2,x3,x4)=y的形式,其中我有包含y、x1、x2、x3和x4值的向量。y=Aexp(-x1(x2B^2 + x3B +x4))。现在y是因变量,而x1、x2、x3和x4是自变量,A和B是我要寻找的常数。因此,算法应该找到这样的A和B来适应我提供的向量。 - darko_5
显示剩余6条评论
1个回答

1

CONOPT由GAMS分发,似乎是GRG的一个成熟实现,但并非免费(尽管演示可能足够您使用)。

Alglib提供了非线性Levenberg-Marquardt算法的实现here,可以选择GPL /商业许可证。

以下是使用alglib的示例代码:

/*
 * Simple optimiser example
 *
 * nl_opt.cpp
 *
 * Compile with eg 'g++ -I../tools/alglib/src ../tools/alglib/src/ap.cpp ../tools/alglib/src/alglibinternal.cpp ../tools/alglib/src/linalg.cpp ../tools/alglib/src/alglibmisc.cpp ../tools/alglib/src/solvers.cpp ../tools/alglib/src/optimization.cpp nl_opt.cpp -o opt'
 *
 */

#include "stdafx.h"
#include <iostream>
#include <cmath>

#include "optimization.h"

using namespace std;

double fn(double a1, double a2, double a3, double x, double A, double B)
{
    return A * exp(-x*(a1*B*B+a2*B+a3));
}

struct problem
{
    double *m_a1s;
    double *m_a2s;
    double *m_a3s;
    double *m_xs;
    double *m_ys;

    int m_n;

    problem(double *a1s, double *a2s, double *a3s, double *xs, double *ys, int n) 
        : m_a1s(a1s), m_a2s(a2s), m_a3s(a3s), m_xs(xs), m_ys(ys), m_n(n)
    {
    }

    void fn_vec(const alglib::real_1d_array &c_var, alglib::real_1d_array &fi, void *ptr)
    {
        double sum = 0.0;
        for(int i = 0; i < m_n; ++i)
        {
            double yhat = fn(m_a1s[i], m_a2s[i], m_a3s[i], m_xs[i], c_var[0], c_var[1]);
            double err_sq = (m_ys[i] - yhat) * (m_ys[i] - yhat);
            sum += err_sq;
        }
        fi[0] = sum;
    }
};

problem *g_p;

void fn_vec(const alglib::real_1d_array &c_var, alglib::real_1d_array &fi, void *ptr)
{
    g_p->fn_vec(c_var, fi, ptr);
}

int main()
{
    cout << "Testing non-linear optimizer..." << endl;

    int n = 5;
    double a1s[] = {2.42, 4.78, 7.25, 9.55, 11.54};
    double a2s[] = {4.25, 5.27, 6.33, 7.32, 8.18};
    double a3s[] = {3.94, 4.05, 4.17, 4.28, 4.37};

    double xs[] = {0.024, 0.036, 0.048, 0.06, 0.072};
    double ys[] = {80, 70, 50, 40, 45};

    double initial[] = {150, 1.75};
    double ss_init = 0.0;

    cout << "Initial problem:" << endl;
    for(int i = 0; i < n; ++i)
    {
        double yhat = fn(a1s[i], a2s[i], a3s[i], xs[i], initial[0], initial[1]);
        double err_sq = (ys[i] - yhat) * (ys[i] - yhat);
        ss_init += err_sq;
        cout << a1s[i] << "\t" << a2s[i] << "\t" << a3s[i] << "\t" 
            << xs[i] << "\t" << ys[i] << "\t" << yhat << "\t" << err_sq << endl;
    }
    cout << "Error: " << ss_init << endl;

    // create problem
    problem p(a1s, a2s, a3s, xs, ys, n);
    g_p = &p;

    // setup solver
    alglib::real_1d_array x = "[150.0, 1.75]";
    double epsg = 0.00000001;
    double epsf = 0;
    double epsx = 0;

    alglib::ae_int_t maxits = 0;
    alglib::minlmstate state;
    alglib::minlmreport report;

    alglib::minlmcreatev(2, x, 0.0001, state);
    alglib::minlmsetcond(state, epsg, epsf, epsx, maxits);

    // optimize
    alglib::minlmoptimize(state, fn_vec);

    alglib::minlmresults(state, x, report);

    cout << "Results:" << endl;

    cout << report.terminationtype << endl;
    cout << x.tostring(2).c_str() << endl;

    double ss_end = 0.0;
    for(int i = 0; i < n; ++i)
    {
        double yhat = fn(a1s[i], a2s[i], a3s[i], xs[i], x[0], x[1]);
        double err_sq = (ys[i] - yhat) * (ys[i] - yhat);
        ss_end += err_sq;
        cout << a1s[i] << "\t" << a2s[i] << "\t" << a3s[i] << "\t"
             << xs[i] << "\t" << ys[i] << "\t" << yhat << "\t" << err_sq << endl;
    }
    cout << "Error: " << ss_end << endl;

    return 0;
}

这是示例输出:

./opt 
Testing non-linear optimizer...
Initial problem:
2.42    4.25    3.94    0.024   80  95.5553 241.968
4.78    5.27    4.05    0.036   70  54.9174 227.485
7.25    6.33    4.17    0.048   50  24.8537 632.338
9.55    7.32    4.28    0.06    40  9.3038  942.257
11.54   8.18    4.37    0.072   45  3.06714 1758.36
Error: 3802.41
Results:
2
[92.22,0.57]
2.42    4.25    3.94    0.024   80  77.6579 5.48528
4.78    5.27    4.05    0.036   70  67.599  5.76475
7.25    6.33    4.17    0.048   50  56.6216 43.8456
9.55    7.32    4.28    0.06    40  46.0026 36.0314
11.54   8.18    4.37    0.072   45  36.6279 70.0922
Error: 161.219

此外,http://stackoverflow.com/questions/13854917/lib-for-nonlinear-fitting-on-ios 指向了这个 MINPACK 实现。不确定你的目标平台是什么? - grayal
我实际上已经使用了Alglib,并将其编译为可与Objective-C一起使用,因为它是针对OS X平台的。 - darko_5
顺便提一下,我已经使用了Alglib的interpolation.h部分,并且我已经阅读过它,它只是优化曲线拟合算法的包装器。希望这是个好决定。 - darko_5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接