C#调用iLog Cplex 输出不收敛的约束

文章讲述了如何使用C#调用iLogCplex的API来解决优化问题。当模型不收敛时,通过保存模型文件,重新导入并分析约束冲突,使用冲突精炼方法找出问题所在。代码示例展示了从检查解决方案状态到识别和处理不约束冲突的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求

    用C#调用 iLog Cplex 的API 求解规划问题,如果模型不收敛(infeasible),需要知道是哪里出了问题,根据IBM管网的Java示例,写一个C#版本。

步骤

    首先,在构造好模型后需要保存模型文件(*.lp)

cplex.ExportModel("optmodel.lp"); 

    然后,判断求解是否成功,如果不成功则执行下文的逻辑

if (cplex.Solve())
{
    ...
}
else
{
    //下方代码
}

       导入optmodel.lp,这样才能获取到矩阵,遍历约束判断是否有冲突,打印冲突的约束,需要时可以打开 optmodel.lp 文件,对照分析约束不满足的原因。

cplex.ImportModel("optmodel.lp");
var matrixEnum = cplex.GetLPMatrixEnumerator();
matrixEnum.MoveNext();
var lp = (ILPMatrix)matrixEnum.Current;
Console.WriteLine($"Solution status = {cplex.GetStatus()}");
Console.WriteLine("Model Infeasible, Calling CONFLICT REFINER");
var rng = lp.Ranges;
int numVars = 0;

//calculate the number of non-boolean variables
for (int c1 = 0; c1 < lp.NumVars.Length; c1++)
	if (lp.NumVars[c1].Type != NumVarType.Bool)
		numVars++;
//find the number of SOSs in the model
int numSOS = cplex.NSOSs;
Console.WriteLine("Number of SOSs=" + numSOS);

int numConstraints = rng.Length + 2 * numVars + numSOS;
var constraints = new IConstraint[numConstraints];
for (int c1 = 0; c1 < rng.Length; c1++)
{
	constraints[c1] = rng[c1];
}
int numVarCounter = 0;
//add variable bounds to the constraints array
for (int c1 = 0; c1 < lp.NumVars.Length; c1++)
{
	if (lp.NumVars[c1].Type != NumVarType.Bool)
	{
		constraints[rng.Length + 2 * numVarCounter] = cplex.AddLe(lp.NumVars[c1].LB, lp.NumVars[c1]);
		constraints[rng.Length + 2 * numVarCounter].Name = lp.NumVars[c1].ToString() + "_LB";
		constraints[rng.Length + 2 * numVarCounter + 1] = cplex.AddGe(lp.NumVars[c1].UB, lp.NumVars[c1]);
		constraints[rng.Length + 2 * numVarCounter + 1].Name = lp.NumVars[c1].ToString() + "_UB";
		numVarCounter++;
	}
}
//add SOSs to the constraints array
if (numSOS > 0)
{
	int s1Counter = 0;
	var s1 = cplex.GetSOS1Enumerator();
	while (s1.MoveNext())
	{
		var cur = (ISOS1)s1.Current;
		Console.WriteLine(cur);
		constraints[rng.Length + numVars * 2 + s1Counter] = cur;
		s1Counter++;
	}
	int s2Counter = 0;
	var s2 = cplex.GetSOS2Enumerator();
	while (s2.MoveNext())
	{
		var cur = (ISOS2)s2.Current;
		Console.WriteLine(cur);
		constraints[rng.Length + numVars * 2 + s1Counter + s2Counter] = cur;
		s2Counter++;
	}
}
double[] prefs = new double[constraints.Length];
for (int c1 = 0; c1 < constraints.Length; c1++)
{
	//Console.WriteLine(constraints[c1]);
	prefs[c1] = 1.0;//change it per your requirements
}
if (cplex.RefineConflict(constraints, prefs))
{
	Console.WriteLine("Conflict Refinement process finished: Printing Conflicts");
	var conflict = cplex.GetConflict(constraints);
	int numConConflicts = 0;
	int numBoundConflicts = 0;
	int numSOSConflicts = 0;
	for (int c2 = 0; c2 < constraints.Length; c2++)
	{
		if (conflict[c2] == Cplex.ConflictStatus.Member)
		{
			Console.WriteLine("  Proved  : " + constraints[c2]);
			if (c2 < rng.Length)
				numConConflicts++;
			else if (c2 < rng.Length + 2 * numVars)
				numBoundConflicts++;
			else
				numSOSConflicts++;

		}
		else if (conflict[c2] == Cplex.ConflictStatus.PossibleMember)
		{
			Console.WriteLine("  Possible  : " + constraints[c2]);
			if (c2 < rng.Length)
				numConConflicts++;
			else if (c2 < rng.Length + 2 * numVars)
				numBoundConflicts++;
			else
				numSOSConflicts++;
		}
	}
	Console.WriteLine("Conflict Summary:");
	Console.WriteLine("  Constraint conflicts     = " + numConConflicts);
	Console.WriteLine("  Variable Bound conflicts = " + numBoundConflicts);
	Console.WriteLine("  SOS conflicts            = " + numSOSConflicts);
}
else
{
	Console.WriteLine("Conflict could not be refined");
}

       还可以进一步打印 Cplex 给出的建议,不过这部分我没用

Console.WriteLine("Calling FEASOPT");
// cplex.SetParam(Cplex.IntParam.FeasOptMode, 0);//change per feasopt requirements
// Relax contraints only, modify if variable bound relaxation is required
double[] lb_pref = new double[rng.Length];
double[] ub_pref = new double[rng.Length];
for (int c1 = 0; c1 < rng.Length; c1++)
{
	lb_pref[c1] = 1.0;//change it per your requirements
	ub_pref[c1] = 1.0;//change it per your requirements
}
if (cplex.FeasOpt(rng, lb_pref, ub_pref))
{
	Console.WriteLine("Finished Feasopt");
	double[] infeas = cplex.GetInfeasibilities(rng);
	//Print bound changes
	Console.WriteLine("Suggested Bound changes:");
	for (int c3 = 0; c3 < infeas.Length; c3++)
		if (infeas[c3] != 0)
			Console.WriteLine("  " + rng[c3] + " : Change=" + infeas[c3]);
	Console.WriteLine("Relaxed Model's obj value=" + cplex.ObjValue);
	Console.WriteLine("Relaxed Model's solution status:" + cplex.GetCplexStatus());
	double[] x = cplex.GetValues(lp);
	for (int j = 0; j < x.Length; ++j)
		Console.WriteLine("Relaxed Model's Variable Name:" + lp.NumVars[j].Name + "; Value = " + x[j]);
}
else
{
	Console.WriteLine("FeasOpt failed- Could not repair infeasibilities");
}

### 如何在 Visual Studio 中通过 C# 调用 CPLEX 进行优化问题求解 #### 准备工作 为了能够在 Visual Studio 的 C# 项目中调用 IBM CPLEX 库,需先下载并安装 CPLEX Optimizer。确保已将 CPLEX 安装路径中的 `bin` 文件夹添加到系统的环境变量 PATH 中[^2]。 #### 创建新项目 启动 Visual Studio 并创建一个新的 WPF 或控制台应用程序项目。对于 WPF 程序而言,可以直接把 CPLEX DLL 所在文件夹下的必要文件复制到项目的根目录下。 #### 添加引用 右键点击解决方案资源管理器中的“引用”,选择“添加引用”。浏览至 CPLEX 安装位置的 `\cplex\lib\netstandard2.0` 目录(具体版本号可能有所同),选中所有 `.dll` 文件并确认添加[^3]。 #### 编写代码实现简单线性规划模型 下面是一个简单的例子来展示如何构建和解决问题: ```csharp using ILOG.Concert; using ILOG.CPLEX; class Program { static void Main(string[] args) { try { using (CPLEX cplex = new CPLEX()) { // 初始化 CPLEX 实例 INumVar x = cplex.NumVar(0, double.PositiveInfinity); // 定义决策变量 INumVar y = cplex.NumVar(0, double.PositiveInfinity); ICplexModeler model = cplex.Model(); // 构建模型 // 设置目标函数最小化 max(x + y) model.AddMaximize(cplex.Sum(new INumExpr[]{x, y})); // 加入约束条件 x + 2y <= 10 和 2x + y >= 8 model.AddLe(cplex.Sum(new INumExpr[]{x, cplex.Prod(y, 2)}), 10); model.AddGe(cplex.Sum(new INumExpr[]{cplex.Prod(x, 2), y}), 8); if (!model.Solve()) throw new Exception("Solving failed"); Console.WriteLine($"Solution status = {cplex.GetStatus()}"); Console.WriteLine($"Objective value = {model.ObjValue()}"); Console.WriteLine($"x = {cplex.GetValue(x)}"); Console.WriteLine($"y = {cplex.GetValue(y)}"); } } catch (IloException e) { Console.WriteLine("Error: " + e.Message); } } } ``` 此段代码展示了怎样定义两个连续型非负数决策变量 \(x\) 和 \(y\) ,设置最大化的目标函数以及加入等式的约束条件,并最终打印出最优解及其对应的目标值[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值