我在.net后端调用了Google OR-Tools的东西来实现线性规划的算法
在最后输出CpSolverStatus status = solver.Solve(model)执行时,

报了该错,应当如何处理
public void TestJoin_ORTools_CalculateMethod()
{
// 产品数据初始化
List<Product> products = new List<Product>
{
new Product { Code = "001", PrimaryCategory = "皮革毛皮", SecondaryCategory = "皮革" },
new Product { Code = "002", PrimaryCategory = "皮革毛皮", SecondaryCategory = "皮革" },
new Product { Code = "003", PrimaryCategory = "皮革毛皮", SecondaryCategory = "皮革" },
new Product { Code = "004", PrimaryCategory = "皮革毛皮", SecondaryCategory = "皮革" },
new Product { Code = "005", PrimaryCategory = "皮革毛皮", SecondaryCategory = "皮革" },
new Product { Code = "006", PrimaryCategory = "织物", SecondaryCategory = "织物" },
new Product { Code = "007", PrimaryCategory = "织物", SecondaryCategory = "织物" },
new Product { Code = "008", PrimaryCategory = "织物", SecondaryCategory = "织物" },
new Product { Code = "009", PrimaryCategory = "织物", SecondaryCategory = "织物" },
new Product { Code = "010", PrimaryCategory = "织物", SecondaryCategory = "织物" },
new Product { Code = "012", PrimaryCategory = "织物", SecondaryCategory = "织物" },
new Product { Code = "015", PrimaryCategory = "织物", SecondaryCategory = "织物" },
new Product { Code = "016", PrimaryCategory = "织物", SecondaryCategory = "织物" }
};
// 优先组合
var priorityGroup1 = new List<string> { "001", "003", "004" };
var priorityGroup2 = new List<string> { "008", "009", "010" };
// 创建求解器模型
CpModel model = new CpModel();
int productCount = products.Count;
int maxGroups = productCount; // 最多分组数
IntVar[] groupAssignments = new IntVar[productCount];
for (int i = 0; i < productCount; i++)
{
groupAssignments[i] = model.NewIntVar(0, maxGroups - 1, $"group_{products[i].Code}");
}
// 2. 决策变量:组是否被使用(布尔值)
BoolVar[] groupUsed = new BoolVar[maxGroups];
IntVar[] groupSizes = new IntVar[maxGroups];
// 存储所有布尔变量的二维数组
BoolVar[,] inGroupFlags = new BoolVar[productCount, maxGroups];
// 3. 创建组使用和组大小变量
for (int g = 0; g < maxGroups; g++)
{
groupUsed[g] = model.NewBoolVar($"group_used_{g}");
List<BoolVar> inGroupList = new List<BoolVar>(); // 使用BoolVar列表
for (int i = 0; i < productCount; i++)
{
// 创建布尔变量
inGroupFlags[i, g] = model.NewBoolVar($"in_group_{i}_{g}");
// 正确使用OnlyEnforceIf
model.Add(groupAssignments[i] == g).OnlyEnforceIf(inGroupFlags[i, g]);
model.Add(groupAssignments[i] != g).OnlyEnforceIf(inGroupFlags[i, g].Not());
inGroupList.Add(inGroupFlags[i, g]);
}
// 计算组大小
groupSizes[g] = model.NewIntVar(0, productCount, $"size_{g}");
model.Add(groupSizes[g] == LinearExpr.Sum(inGroupList));
// 组使用约束
model.Add(groupSizes[g] > 0).OnlyEnforceIf(groupUsed[g]);
model.Add(groupSizes[g] == 0).OnlyEnforceIf(groupUsed[g].Not());
}
// 4. 约束:每个产品必须属于一个组
for (int i = 0; i < productCount; i++)
{
List<ILiteral> groupOptions = new List<ILiteral>();
for (int g = 0; g < maxGroups; g++)
{
groupOptions.Add(inGroupFlags[i, g]);
}
model.AddExactlyOne(groupOptions);
}
// 5. 约束:组大小不超过4
for (int g = 0; g < maxGroups; g++)
{
model.Add(groupSizes[g] <= 4);
}
// 6. 优先组合约束
ApplyPriorityGrouping(model, products, groupAssignments, priorityGroup1);
ApplyPriorityGrouping(model, products, groupAssignments, priorityGroup2);
// 7. 分类一致性约束
AddCategoryConstraints(model, products, groupAssignments);
// 8. 4个产品时的特殊处理
IntVar totalGroups = model.NewIntVar(0, maxGroups, "total_groups");
model.Add(totalGroups == LinearExpr.Sum(groupUsed));
// 9. 目标函数:最大化分类一致性
//IntVar secondaryMatchScore = model.NewIntVar(0, productCount * 10, "secondary_match");
//IntVar primaryMatchScore = model.NewIntVar(0, productCount * 5, "primary_match");
//IntVar groupSizePenalty = model.NewIntVar(0, productCount * 3, "group_size_penalty");
CalculateCategoryScores(model, products, groupAssignments, groupUsed, groupSizes,out IntVar secondaryMatchScore, out IntVar primaryMatchScore, out IntVar groupSizePenalty);
// 最终目标:优先二级分类,其次一级分类,最后最小化组大小惩罚
model.Maximize(secondaryMatchScore * 1000 + primaryMatchScore * 100 - groupSizePenalty * 10);
// 10. 创建求解器
CpSolver solver = new CpSolver();
solver.StringParameters = "num_search_workers:8, max_time_in_seconds:30, log_search_progress:true";
CpSolverStatus status = solver.Solve(model);
// 11. 输出结果
if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible)
{
PrintSolution(solver, products, groupAssignments, groupUsed, maxGroups);
}
else
{
Console.WriteLine("未找到可行解决方案");
}
}
/// <summary>
/// 应用优先组合约束
/// </summary>
/// <param name="model"></param>
/// <param name="products"></param>
/// <param name="groupAssignments"></param>
/// <param name="priorityCodes"></param>
private static void ApplyPriorityGrouping(CpModel model, List<Product> products,IntVar[] groupAssignments, List<string> priorityCodes)
{
List<int> indices = new List<int>();
foreach (string code in priorityCodes)
{
int idx = products.FindIndex(p => p.Code == code);
if (idx >= 0) indices.Add(idx);
}
if (indices.Count == priorityCodes.Count)
{
// 强制所有产品在同一组
for (int i = 1; i < indices.Count; i++)
{
model.Add(groupAssignments[indices[0]] == groupAssignments[indices[i]]);
}
// 添加分类一致性约束
for (int i = 0; i < indices.Count; i++)
{
for (int j = i + 1; j < indices.Count; j++)
{
Product p1 = products[indices[i]];
Product p2 = products[indices[j]];
if (p1.SecondaryCategory != p2.SecondaryCategory)
{
Console.WriteLine($"警告: 优先组合 {string.Join(",", priorityCodes)} 中的产品 {p1.Code} 和 {p2.Code} 二级分类不一致");
}
}
}
}
}
/// <summary>
/// 添加分类一致性约束
/// </summary>
/// <param name="model"></param>
/// <param name="products"></param>
/// <param name="groupAssignments"></param>
private static void AddCategoryConstraints(CpModel model, List<Product> products,IntVar[] groupAssignments)
{
for (int i = 0; i < products.Count; i++)
{
for (int j = i + 1; j < products.Count; j++)
{
// 不同一级分类的产品不能在同一组
if (products[i].PrimaryCategory != products[j].PrimaryCategory)
{
BoolVar sameGroup = model.NewBoolVar($"same_group_{i}_{j}");
model.Add(groupAssignments[i] == groupAssignments[j]).OnlyEnforceIf(sameGroup);
model.Add(groupAssignments[i] != groupAssignments[j]).OnlyEnforceIf(sameGroup.Not());
model.Add(sameGroup == 0);
}
}
}
}
/// <summary>
/// 计算分类一致性分数
/// </summary>
/// <param name="model"></param>
/// <param name="products"></param>
/// <param name="groupAssignments"></param>
/// <param name="groupUsed"></param>
/// <param name="groupSizes"></param>
/// <param name="secondaryMatchScore"></param>
/// <param name="primaryMatchScore"></param>
/// <param name="groupSizePenalty"></param>
private static void CalculateCategoryScores(CpModel model, List<Product> products, IntVar[] groupAssignments, BoolVar[] groupUsed, IntVar[] groupSizes, out IntVar secondaryMatchScore, out IntVar primaryMatchScore, out IntVar groupSizePenalty)
{
List<IntVar> secondaryScores = new List<IntVar>();
List<IntVar> primaryScores = new List<IntVar>();
List<IntVar> sizePenalties = new List<IntVar>();
// 1. 计算分类匹配得分
for (int i = 0; i < products.Count; i++)
{
for (int j = i + 1; j < products.Count; j++)
{
// 使用 BoolVar 而不是 IntVar
BoolVar sameGroup = model.NewBoolVar($"same_group_{i}_{j}");
model.Add(groupAssignments[i] == groupAssignments[j]).OnlyEnforceIf(sameGroup);
model.Add(groupAssignments[i] != groupAssignments[j]).OnlyEnforceIf(sameGroup.Not());
// 二级分类匹配得分
if (products[i].SecondaryCategory == products[j].SecondaryCategory)
{
secondaryScores.Add(sameGroup);
}
// 一级分类匹配得分
else if (products[i].PrimaryCategory == products[j].PrimaryCategory)
{
primaryScores.Add(sameGroup);
}
}
}
// 2. 计算组大小惩罚
for (int g = 0; g < groupUsed.Length; g++)
{
// 定义布尔变量而不是 IntVar
BoolVar isSize2 = model.NewBoolVar($"is_size2_{g}");
BoolVar isSize3 = model.NewBoolVar($"is_size3_{g}");
// 添加约束
model.Add(groupSizes[g] == 2).OnlyEnforceIf(isSize2);
model.Add(groupSizes[g] != 2).OnlyEnforceIf(isSize2.Not());
model.Add(groupSizes[g] == 3).OnlyEnforceIf(isSize3);
model.Add(groupSizes[g] != 3).OnlyEnforceIf(isSize3.Not());
// 定义非理想大小变量 (BoolVar)
BoolVar notIdealSize = model.NewBoolVar($"not_ideal_{g}");
// 修复 AddBoolOr 调用 - 使用集合
model.AddBoolOr(new ILiteral[] { isSize2, isSize3 })
.OnlyEnforceIf(notIdealSize.Not());
// 修复 AddBoolAnd 调用 - 使用集合
model.AddBoolAnd(new ILiteral[] { isSize2.Not(), isSize3.Not() })
.OnlyEnforceIf(notIdealSize);
// 惩罚值变量
IntVar penalty = model.NewIntVar(0, 10, $"penalty_{g}");
// 惩罚条件:组被使用且大小不理想
BoolVar penalizeCondition = model.NewBoolVar($"penalize_cond_{g}");
model.AddBoolAnd(new ILiteral[] { groupUsed[g], notIdealSize })
.Equals(penalizeCondition);
// 设置惩罚值
model.Add(penalty == 0).OnlyEnforceIf(penalizeCondition.Not());
model.Add(penalty == groupSizes[g]).OnlyEnforceIf(penalizeCondition);
sizePenalties.Add(penalty);
}
// 创建输出变量
secondaryMatchScore = model.NewIntVar(0, secondaryScores.Count, "secondary_match_score");
model.Add(secondaryMatchScore == LinearExpr.Sum(secondaryScores));
primaryMatchScore = model.NewIntVar(0, primaryScores.Count, "primary_match_score");
model.Add(primaryMatchScore == LinearExpr.Sum(primaryScores));
groupSizePenalty = model.NewIntVar(0, sizePenalties.Count * 4, "group_size_penalty");
model.Add(groupSizePenalty == LinearExpr.Sum(sizePenalties));
}
/// <summary>
/// 打印解决方案
/// </summary>
/// <param name="solver"></param>
/// <param name="products"></param>
/// <param name="groupAssignments"></param>
/// <param name="groupUsed"></param>
/// <param name="maxGroups"></param>
private static void PrintSolution(CpSolver solver, List<Product> products,
IntVar[] groupAssignments, IntVar[] groupUsed, int maxGroups)
{
// 收集分组结果
Dictionary<int, List<Product>> groups = new Dictionary<int, List<Product>>();
for (int i = 0; i < products.Count; i++)
{
int groupId = (int)solver.Value(groupAssignments[i]);
if (!groups.ContainsKey(groupId))
groups[groupId] = new List<Product>();
groups[groupId].Add(products[i]);
}
// 打印分组信息
Console.WriteLine("优化后的分组方案:");
foreach (var group in groups.Values)
{
if (group.Count == 0) continue;
// 验证分类一致性
string primaryCat = group[0].PrimaryCategory;
string secondaryCat = group[0].SecondaryCategory;
bool primaryConsistent = group.All(p => p.PrimaryCategory == primaryCat);
bool secondaryConsistent = group.All(p => p.SecondaryCategory == secondaryCat);
string consistency = secondaryConsistent ? "二级分类一致" :
primaryConsistent ? "一级分类一致" : "分类不一致!";
Console.WriteLine($"- 组 ({string.Join(", ", group.Select(p => p.Code))}) " +
$"[大小: {group.Count}, 分类: {primaryCat}/{secondaryCat}, 一致性: {consistency}]");
}
// 打印统计信息
int totalGroups = groups.Count(g => g.Value.Count > 0);
int threePersonGroups = groups.Count(g => g.Value.Count == 3);
int twoPersonGroups = groups.Count(g => g.Value.Count == 2);
int onePersonGroups = groups.Count(g => g.Value.Count == 1);
Console.WriteLine($"\n分组统计:");
Console.WriteLine($"- 总组数: {totalGroups}");
Console.WriteLine($"- 3人组数量: {threePersonGroups}");
Console.WriteLine($"- 2人组数量: {twoPersonGroups}");
Console.WriteLine($"- 1人组数量: {onePersonGroups}");
Console.WriteLine($"- 求解状态: {solver.ResponseStats()}");
Console.WriteLine($"- 目标值: {solver.ObjectiveValue}");
}