lxysoid 2025-06-02 19:13 采纳率: 0%
浏览 24

Google OR-Tools 的错误

我在.net后端调用了Google OR-Tools的东西来实现线性规划的算法

在最后输出CpSolverStatus status = solver.Solve(model)执行时,

img

报了该错,应当如何处理

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}");
        }

  • 写回答

6条回答 默认 最新

  • 阿里嘎多学长 2025-06-02 19:14
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    Google OR-Tools 的错误

    你在使用 Google OR-Tools 的 .NET 版本实现线性规划算法时,遇到了错误。错误发生在 CpSolverStatus status = solver.Solve(model) 这行代码中。

    可能的解决方案:

    1. 检查模型是否正确:确保模型中的变量、约束和目标函数正确无误。
    2. 检查 solver 的设置:确保 solver 的设置正确,例如,是否正确地设置了时间限制、线性搜索的深度等。
    3. 检查 solver 的状态:使用 solver.Status 属性来检查 solver 的当前状态,了解错误的原因。
    4. 检查日志信息:使用 solver.Log 属性来获取 solver 的日志信息,了解错误的原因。

    以下是一个简单的示例代码,用于检查 solver 的状态:

    CpSolverStatus status = solver.Solve(model);
    if (status == CpSolverStatus.Optimal)
    {
        // 模型已经被求解
    }
    else if (status == CpSolverStatus.Feasible)
    {
        // 模型可以被求解,但没有找到最优解
    }
    else if (status == CpSolverStatus.Infeasible)
    {
        // 模型不可行
    }
    else
    {
        // 其他错误
    }
    

    如果你仍然无法解决问题,请提供更多的错误信息和代码,我将尽力帮助你解决问题。

    评论

报告相同问题?

问题事件

  • 修改了问题 6月2日
  • 创建了问题 6月2日