【问题标题】:OR Tools setting a variable with multiple indices in Java或工具在 Java 中设置具有多个索引的变量
【发布时间】:2019-07-14 14:52:32
【问题描述】:

我正在尝试形成一个具有多个索引的变量,例如$x_{i,j}$

到目前为止,我在文档中发现了以下变量的简单设置:

MPVariable x = solver.makeIntVar(0.0, infinity, "x");

是否有任何文档显示这样的示例?

此外,是否可以在 OR 工具中使用 AMPL 来表述问题?

【问题讨论】:

    标签: java ampl or-tools integer-programming


    【解决方案1】:

    您只需为每对索引创建一个变量;即循环ij并创建一个ArrayList<ArrayList<MPVariable>>;即执行以下操作,其中ninj 分别表示索引ij 的值的数量:

    var x = new ArrayList<ArrayList<MPVariable>>();
    for (int i = 0; i < ni; i++) {
        var inner = new ArrayList<MPVariable>();
        for (int j = 0; j < nj; j++) {
            var xij = solver.makeIntVar(0.0, infinity, String.format("x%d%d", i, j));
            inner.add(xij);
        }
        x.add(inner);
    }
    

    此时您可以通过x.get(i).get(j) 访问$x_{i,j}$。

    官方文档有这方面的例子,尽管是针对 CP 求解器的;参见例如the solution to the N-queens problem。在这里,示例使用 Python API,但您可以将其转换为 Java;作为参考,上面的嵌套循环在 Python 中如下所示:

    x = [[solver.IntVar(0.0, infinity, f'x{i}{j}') for j in range(nj)] for i in range(ni)]
    

    完整的工作示例:分配问题

    考虑到这一点,让我们尝试创建一个完整的示例。一个由整数变量的二维矩阵建模的简单问题是linear assignment problem。在最简单的形式中,我们得到一个权重的实方阵 $(w_{ij})_{ij}$ 并试图最小化 $\sum_{ij} w_{ij} x_{ij}$ 其中每个 $x_ {ij}$ 为 0 或 1,其中对于每个 $i$,恰好有一个 $x_{ij}$ 为 1,同样,对于每个 $j$,恰好 $x_{ij}$ 为 1。

    在这里,让我们创建一个 5x5 实例,其中 $w_{ij} = (i+1)(j+1)$。很容易验证,在这种情况下,最佳解决方案是让 $x_{04} = x_{13} = x_{22} = x_{31} = x_{40} = 1$,并让所有其他值 $ x_{ij}$ 为 0,则目标值为 5 + 8 + 9 + 8 + 5 = 35。

    以下是解决这种情况并打印结果的完整程序:

    import com.google.ortools.linearsolver.MPConstraint;
    import com.google.ortools.linearsolver.MPObjective;
    import com.google.ortools.linearsolver.MPSolver;
    import com.google.ortools.linearsolver.MPVariable;
    import java.util.ArrayList;
    
    public class LinearAssignment {
        public static void main(String[] args) {
            System.loadLibrary("jniortools");
            var solver = new MPSolver(
                    "LinearAssignmentProblem", MPSolver.OptimizationProblemType.valueOf("CBC_MIXED_INTEGER_PROGRAMMING"));
    
            // Define the variables and the objective function
            var x = new ArrayList<ArrayList<MPVariable>>();
            var objective = solver.objective();
            int n = 5;
            for (int i = 0; i < n; i++) {
                var inner = new ArrayList<MPVariable>();
                for (int j = 0; j < n; j++) {
                    var xij = solver.makeBoolVar(String.format("x%d%d", i, j));
                    objective.setCoefficient(xij, (i+1)*(j+1));
                    inner.add(xij);
                }
                x.add(inner);
            }
    
            // Add the constraint that sum_j x_{ij} = 1 for every i.
            for (int i = 0; i < n; i++) {
                var ci = solver.makeConstraint(1, 1);
                for (int j = 0; j < n; j++) ci.setCoefficient(x.get(i).get(j), 1);
            }
    
            // Add the constraint that sum_i x_{ij} = 1 for every j.
            for (int i = 0; j < n; j++) {
                var cj = solver.makeConstraint(1, 1);
                for (int i = 0; i < n; i++) cj.setCoefficient(x.get(i).get(j), 1);
            }
    
            // Run the solver
            solver.solve();
    
            // Print the results
            System.out.println("Objective at minimum = " + solver.objective().value());
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++)
                    System.out.print(String.format("x%d%d = %d, ", i, j, (int) x.get(i).get(j).solutionValue()));
                System.out.println();
            }
        }
    }
    

    输出:

    Objective at minimum = 35.0
    x00 = 0, x01 = 0, x02 = 0, x03 = 0, x04 = 1,
    x10 = 0, x11 = 0, x12 = 0, x13 = 1, x14 = 0,
    x20 = 0, x21 = 0, x22 = 1, x23 = 0, x24 = 0,
    x30 = 0, x31 = 1, x32 = 0, x33 = 0, x34 = 0,
    x40 = 1, x41 = 0, x42 = 0, x43 = 0, x44 = 0,
    

    需要注意的是这里的解决方案主要是说明性的,这个问题实际上可以简化一点:由于 $x_{ij}$ 要么是 0 要么是 1,我们可以使用 makeBoolVar 而不是 @987654336 @。但事实上,由于约束矩阵是完全单模的,我们实际上根本不需要使用整数变量,而可以使用实值 $0 \leq x_{ij} \leq 1$。

    此外,存在解决线性分配问题的有效算法;实际上,OR-Tools 本身为整数值权重捆绑了 CSA-Q 算法的实现,该算法在实践中运行良好。不过,该解决方案适用于较小的问题实例,并有望用作说明如何使用 MPSolver 解决重要问题的示例。

    【讨论】:

    • 对我来说仍然不够清楚。如果我写以下内容:ArrayList&lt;ArrayList&lt;MPVariable&gt;&gt; x = new ArrayList&lt;ArrayList&lt;MPVariable&gt;&gt;(); 并想使用 set 方法:x.set(int index, ArrayList&lt;MPVariable&gt; element) 我在哪里使用索引 ij
    • 我已经更新了答案以扩展我的想法。
    • 如果我想使用相同的约束 \forall 集合的元素,我是否必须重命名约束变量?在您的示例中,var ci = solver.makeConstraint(1, 1); c_i 是我的意思的变量。使用 c_{i,1}; 对我来说似乎是合乎逻辑的。 ... ;c_{i,n} 其中 n 是集合中元素的基数。以我的经验,在 Java 中这样的命名是不可能的。还是我只需要使用var ci = solver.makeConstraint(1, 1,"ci"+index); 与您的代码示例,两者中的后者更有意义。
    • 您不必为约束提供名称;在我的示例中,在循环的每次迭代中都会创建一个新的ci,即使变量的名称没有改变,它们最终也会对求解器产生不同的约束(它永远不会看到变量,因此它无法基于此进行区分)。如果您确实想为求解器提供一个名称,那么是的,您将按照后一种方法进行操作。提供名称可以简化调试,但不是必需的(正如线性赋值示例所建议的那样)。
    • 也许使用k 来组合这两个循环是令人困惑的,所以让我编辑示例来拆分它。
    猜你喜欢
    • 1970-01-01
    • 2013-05-27
    • 2016-02-19
    • 2019-05-16
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多