c#与Lingo混合编程解决整数二次规划(非线性规划)问题

Lingo安装完后在其目录下有一些实例项目可以学习如下图所示,实例中讲的是关于线性规划:生产电脑最大利润问题,本章节进行改编:整形非线性规划问题。

(请注意,吐槽开始!!!!!
VS2010下,适用于控制台命令窗口,winform, webform 下述是以控制台窗口调用实例。
当遇到以下情况,改一下目标平台为anycpu,控制台命令窗口,winform即可解决并VS运行正常,但是webform仍然出错,网上查了好多解决方法,如IIS应用池32,64 适配true; 项目.csproj 添加

<Prefer64Bit>false</Prefer64Bit> 或<Prefer32Bit>false</Prefer32Bit> 

最后才发现其实没有问题,虽然在VS上运行出错,但是项目发布后正常运行,真是兜兜转转一大圈花费了1个星期才发现什么都不用改。)
在这里插入图片描述以下是lingo自带项目实例:
在这里插入图片描述
本次要解决的是以下二次整数规划问题求解:

目标函数:
min=(x1-80)^2 + (x2-10)^2 + (x3-10)^2
约束条件:
-x1 * 0.216 -x2 * 0.392 +x3 * 2.120 = y1;
-x1 * 0.0020-x2 * 0.176 + x3 * 0.336 =y2;
-x1 * (1-0.0943)* 0.282 -x2 (1-0.0833) 0.462 + x3 * (1-0.087)* 0.296 = y3;
1< x1,x2,x3<99; 其为整数!!!!!
-0.5<y1,y2,y3<0.5;
x1+x2+x3 =100;


目标函数改成:
min= 1* x1^2 + 1* x2^2 + 1* x3^2 -160x1 -20x2 -20x3 + 840;
约束条件,进行转换成小于等于的形式。例如y1条件如下,
-x1 * 0.216 -x2 * 0.392 +x3 * 2.120 <= 0.5;
x1 * 0.216 -x2 * -0.392 +x3 * -2.120 <= 0.5;

首先解决通过Lingo软件如何求最优解:
c1:目标函数二次项的系数 上述目标函数x1,x2,x3 分别为:1,1,1
c2:目标函数一次项的系数
a:约束条件等式左边的系数:共6行3列,(必须是计算后的值,c#项目中可以带式子,不用全部计算出来)
b:约束条件等式右边的系数
gin(x) 限制整数
bnd() 限制范围

在这里插入图片描述

接下来是在c# 项目中将上述的c1,c2,a,b手动输入,调用lingo解决。

首先lingo改成如下:
pointer(n):1-4: 需要动态输入。 5-7:返回的结果
在这里插入图片描述

c#项目中代码如下:
代码有点多,请耐心观看。
本例是根据例子改变而成,主要的区别是在于c1,c2,a,b的书写格式。一般的流程就是调用dll方法打开指定目录的lng文件,成功后输入参数,在打印结果。
@pointer 内存开辟,方便双方交互,注意c#项目插入时的顺序一一对应。
@status是状态码,可能值:0-9,如果不是0.4.6时将不可信。原例中值判断status为0,即全局最优才输出,其余不打印并报错。而在本例中c#调用Lingo,可能为6,即局部最优,所以也打印。


using System;
using System.IO;
using System.Runtime.InteropServices;

// Our data structure to pass to the callback function
//[StructLayout(LayoutKind.Sequential)]
public struct CallbackData
{
    public int nCallbacks;
    public int nIterations;
    public double dObjective;
}

public class Class1
{

    //我们需要内存指针来向行话传递数据。
    //为了使用指针,必须将例程声明为“不安全”。 

    public unsafe static void Main(string[] args)
    {
        int nError = -1, nPointersNow = -1;
        const string strModelFile = "\\lingo64_17\\programming samples\\c#net\\simple1\\simple.lng"; // Model file name

        // Make sure model file exists
        if (!File.Exists(strModelFile))
        {
           Console.WriteLine("*** Unable to find model file: {0}\n", strModelFile);
           goto FinalExit;
        }

        // Get a pointer to a Lingo environment
        IntPtr pLingoEnv; 
        pLingoEnv = lingo.LScreateEnvLng();
        if (pLingoEnv == IntPtr.Zero)
        {
            Console.WriteLine( "Unable to create Lingo environment.\n");
            goto FinalExit;
        }

        // Open LINGO's log file  
        nError = lingo.LSopenLogFileLng( pLingoEnv, "\\lingo64_17\\programming samples\\c#net\\simple1\\lingo.log");
        if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

        //在下面的代码中,我们建立回调函数。解算器模型处理时,解算器周期性地调用回调。
        //每当Lingo遇到错误时,都会调用错误回调。
        //回调是可选的——如果不是,则不必声明它们需要。
        //可选地,声明回调数据(在全局上分配防止gc重新定位的堆)

        CallbackData cbData;
        cbData.nCallbacks = 0;
        cbData.nIterations = -1;
        cbData.dObjective = 0.0;
        IntPtr myData = Marshal.AllocHGlobal( Marshal.SizeOf( cbData));
        Marshal.StructureToPtr(cbData, myData, true);

        // Pass a pointer to the solver callback and our data
        lingo.typCallback cb = new lingo.typCallback( Class1.MyCallback);
        nError = lingo.LSsetCallbackSolverLng( pLingoEnv, cb, myData);
        if ( nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

        // Pass a pointer to the error callback and our data
        lingo.typCallbackError cbError = new lingo.typCallbackError(Class1.MyErrorCallback);
        nError = lingo.LSsetCallbackErrorLng(pLingoEnv, cbError, myData);
        if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

        //必须将lingo的传输区域固定在内存中,以防止GC重新定位。C类#
        //是一种内存管理语言。这意味着垃圾收集器可以重新定位
        //行话的转移区域,如果他们没有被钉住。
        //下面的每个内存位置都由Lingo的@POINTER(n)函数访问
        //在Lingo模型中,n是感兴趣的内存位置的索引。

        fixed (double* c1 = new double[3] { 1, 1, 1 })  
        fixed (double* c2 = new double[3] { -160, -20, -20})
        fixed (double* a = new double[6, 3]{ { -0.216,-0.392,2.120 }, 
                                            { 0.216,0.392,-2.120 },
                                            {-0.02,-0.176,0.336 },
                                            {0.02,0.176,-0.336 },
                                            { -(1-0.0943)*0.282,-(1-0.0833)*0.462,(1-0.087)*2.698 },
                                            { (1-0.0943)*0.282,(1-0.0833)*0.462,-(1-0.087)*2.698 }

                                           })
        fixed (double* b = new double[6] { 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 }) 
        fixed (double* pdObjective = new double[1] {-1})
        fixed (double* pdStatus = new double[1] {-1})
        fixed (double* x = new double[3] {1,1,1})
        {

            // Pass /Lingo the addresses of the transfer areas for input and output data:
            // Pass Lingo the pointer to the objective coefficients (refer to the template model, simple.lng)

            //将输入和输出数据传输区域的地址用行话传递给:
            //将指针传递给目标系数(请参阅模板模型simple.lng)

            nError = lingo.LSsetPointerLng(pLingoEnv, c1, ref nPointersNow);
            if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

            // Pass a pointer to the production limits //将指针传递到生产限制
            nError = lingo.LSsetPointerLng(pLingoEnv, c2, ref nPointersNow);
            if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

            // Pointer to the labor utilization coefficients      //指向劳动利用系数的指针 
            nError = lingo.LSsetPointerLng(pLingoEnv, a, ref nPointersNow);
            if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

            nError = lingo.LSsetPointerLng(pLingoEnv, b, ref nPointersNow);
            if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

            // Point to dObjective, where Lingo will return the objective value     //指向dObjective,其中Lingo将返回目标值 
            nError = lingo.LSsetPointerLng(pLingoEnv, pdObjective, ref nPointersNow);
            if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

            // Pointer to the solution status code      //指向解决方案状态代码的指针 
            nError = lingo.LSsetPointerLng(pLingoEnv, pdStatus, ref nPointersNow);
            if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

            // Point to the variable value array      //指向变量值数组 
            nError = lingo.LSsetPointerLng(pLingoEnv, x, ref nPointersNow);
            if (nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;
            
            //这是我们要运行LINGO的脚本。这个“take”命令加载
            //从外部文件建模。或者,cScript可以被加载通过使用模型文本,来避免文件访问。 

            string cScript = "set echoin 1 \n";
            cScript += "take \\lingo64_17\\programming samples\\c#net\\simple1\\simple.lng \n";
            cScript += "go \n"; 
            cScript += "quit \n";

            // Clear out the status value;
            pdStatus[ 0] = -1;

            //运行脚本。这里的错误代码只与脚本是否已成功加载以进行处理。我们检查
            //下面的解决方案是检查pdStatus中行话返回的状态值。 


            nError = lingo.LSexecuteScriptLng( pLingoEnv, cScript);
            if ( nError != lingo.LSERR_NO_ERROR_LNG) goto ErrorExit;

            // Close the log file
            lingo.LScloseLogFileLng( pLingoEnv);

            // Any problems?
            if ( nError != 0 ||
            // Check for optimal solution
            pdStatus[ 0] != lingo.LS_STATUS_GLOBAL_LNG)
            {
                // Had a problem   
                Console.WriteLine("Unable to solve! status:" + pdStatus[0]);
                Console.WriteLine(
                "\nx11: {0} \nx21: {1} \nx31: {2} \nx4: {3} \n\nProfit: {4}",
                 x[0], x[1], x[2], x[3], pdObjective[0]);
            } else  {
                // Everything went OK ... print results
                Console.WriteLine("-----------:" + pdStatus[0]);
                Console.WriteLine(
                 "\nx11: {0} \nx21: {1} \nx31: {2}  \n\nProfit: {3}",
                  x[0], x[1], x[2], pdObjective[0]);
            }
        }

        Console.WriteLine();

        // Marshal callnack data back to the structure
        cbData = (CallbackData) Marshal.PtrToStructure(myData,typeof(CallbackData));
        Console.WriteLine( "Total callbacks : {0}" , cbData.nCallbacks);

        // free user data in global heap
        Marshal.FreeHGlobal( myData);

        goto NormalExit;

    ErrorExit:
        Console.WriteLine( "LINGO Error Code: {0}\n", nError);

    NormalExit:
        // Free Lingo's envvironment to avoid a memory leak
        lingo.LSdeleteEnvLng(pLingoEnv);

    FinalExit:
        Console.WriteLine("\nPress enter...");
        String sTemp = Console.ReadLine();
    }
     
    public static int MyCallback(IntPtr pLingoEnv, int nLoc, IntPtr myData)
    {
        // copy the user data in the unmanaged code into a local structure
        CallbackData cb = (CallbackData)Marshal.PtrToStructure(myData, typeof(CallbackData));

        // increment the number of calls to the callback function
        cb.nCallbacks++;

        // get iteration count
        int nIterations = -1, nErr;
        nErr = lingo.LSgetCallbackInfoLng(pLingoEnv,
         lingo.LS_IINFO_ITERATIONS_LNG, ref nIterations);
        if (nErr == lingo.LSERR_NO_ERROR_LNG && nIterations != cb.nIterations)
        {
            cb.nIterations = nIterations;
            Console.WriteLine("Current iteration count in callback={0}", nIterations);
        }

        // get current objective
        double dObjective = 0.0;
        nErr = lingo.LSgetCallbackDblInfoLng(pLingoEnv,
         lingo.LS_DINFO_OBJECTIVE_LNG, ref dObjective);
        if (nErr == lingo.LSERR_NO_ERROR_LNG && dObjective != cb.dObjective && dObjective > 0.0)
        {
            cb.dObjective = dObjective;
            Console.WriteLine("Current objective in callback={0}", dObjective);
        }

        // copy the user data in the local structure back to the unmanaged code
        Marshal.StructureToPtr(cb, myData, false);

        // can return -1 here to interrupt the solver
        return 0;
    }

    public static int MyErrorCallback(IntPtr pLingoEnv, IntPtr myData, int nErrorCode, string strErrorMessage)
    {
       // copy the user data in the unmanaged code into a local structure
       CallbackData cb = (CallbackData)Marshal.PtrToStructure(myData, typeof(CallbackData));
       Console.WriteLine("*** Lingo Error Message: ");
       Console.WriteLine( strErrorMessage + "\n");
       return 0;
    }

}

c#运行结果如下:
在这里插入图片描述

lingo单独运行如下:
在这里插入图片描述
以上就是整个流程,写的有些简单,lingo文件的语法需要查阅资料,不在详细解释。主要是思路,希望对大家有帮助。
上述的满足条件要注意:
1:目标函数为非线性函数中的二次函数
2:约束条件线性函数等式和不等式。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值