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:约束条件线性函数等式和不等式。