// Print out the objective function. // Note that the quadratic expression in the objective // is normalized: i.E., for all i != j, terms // c(i,j)*x[i]*x[j] + c(j,i)*x[j]*x[i] is normalized as // (c(i,j) + c(j,i)) * x[i]*x[j], or // (c(i,j) + c(j,i)) * x[j]*x[i]. internal static void PrintObjective(IObjective obj) { System.Console.WriteLine("obj: " + obj); // Count the number of linear terms // in the objective function. int nlinterms = 0; ILinearNumExprEnumerator len = ((ILQNumExpr)obj.Expr).GetLinearEnumerator(); while (len.MoveNext()) { ++nlinterms; } // Count the number of quadratic terms // in the objective function. int nquadterms = 0; int nquaddiag = 0; IQuadNumExprEnumerator qen = ((ILQNumExpr)obj.Expr).GetQuadEnumerator(); while (qen.MoveNext()) { ++nquadterms; INumVar var1 = qen.GetNumVar1(); INumVar var2 = qen.GetNumVar2(); if (var1.Equals(var2)) { ++nquaddiag; } } System.Console.WriteLine("number of linear terms in the objective : " + nlinterms); System.Console.WriteLine("number of quadratic terms in the objective : " + nquadterms); System.Console.WriteLine("number of diagonal quadratic terms in the objective : " + nquaddiag); System.Console.WriteLine(); }
// This method separates Benders' cuts violated by the current x solution. // Violated cuts are found by solving the worker LP // public IRange Separate(double[][] xSol, IIntVar[][] x) { int i, j, k; IRange cut = null; // Update the objective function in the worker LP: // minimize sum(k in V0) sum((i,j) in A) x(i,j) * v(k,i,j) // - sum(k in V0) u(k,0) + sum(k in V0) u(k,k) ILinearNumExpr objExpr = cplex.LinearNumExpr(); for (k = 1; k < numNodes; ++k) { for (i = 0; i < numNodes; ++i) { for (j = 0; j < numNodes; ++j) { objExpr.AddTerm(v[k - 1][i][j], xSol[i][j]); } } } for (k = 1; k < numNodes; ++k) { objExpr.AddTerm(u[k - 1][k], 1.0); objExpr.AddTerm(u[k - 1][0], -1.0); } cplex.GetObjective().Expr = objExpr; // Solve the worker LP cplex.Solve(); // A violated cut is available iff the solution status is Unbounded if (cplex.GetStatus().Equals(Cplex.Status.Unbounded)) { // Get the violated cut as an unbounded ray of the worker LP ILinearNumExpr rayExpr = cplex.Ray; // Compute the cut from the unbounded ray. The cut is: // sum((i,j) in A) (sum(k in V0) v(k,i,j)) * x(i,j) >= // sum(k in V0) u(k,0) - u(k,k) ILinearNumExpr cutLhs = cplex.LinearNumExpr(); double cutRhs = 0.0; ILinearNumExprEnumerator rayEnum = rayExpr.GetLinearEnumerator(); while (rayEnum.MoveNext()) { INumVar var = rayEnum.NumVar; bool varFound = false; for (k = 1; k < numNodes && !varFound; ++k) { for (i = 0; i < numNodes && !varFound; ++i) { for (j = 0; j < numNodes && !varFound; ++j) { if (var.Equals(v[k - 1][i][j])) { cutLhs.AddTerm(x[i][j], rayEnum.Value); varFound = true; } } } } for (k = 1; k < numNodes && !varFound; ++k) { for (i = 0; i < numNodes && !varFound; ++i) { if (var.Equals(u[k - 1][i])) { if (i == 0) { cutRhs += rayEnum.Value; } else if (i == k) { cutRhs -= rayEnum.Value; } varFound = true; } } } } cut = cplex.Ge(cutLhs, cutRhs); } return(cut); } // END Separate