def getsocpconstrmultipliers(cplex, dslack=None): socppi = dict() # Compute full dual slack (sum of dual multipliers for bound constraints # and per-constraint dual slacks) dense = dict( zip(cplex.variables.get_names(), cplex.solution.get_reduced_costs())) for n in cplex.quadratic_constraints.get_names(): v = cplex.solution.get_quadratic_dualslack(n) for (var, val) in zip(v.ind, v.val): dense[cplex.variables.get_names(var)] += val # Find the cone head variables and pick up the dual slacks for them. for n in cplex.quadratic_constraints.get_names(): q = cplex.quadratic_constraints.get_quadratic_components(n) for (i1, i2, v) in zip(q.ind1, q.ind2, q.val): if v < 0: name = cplex.variables.get_names(i1) socppi[n] = dense[name] break if dslack is not None: dslack.clear() for key, value in six.iteritems(dense): dslack[key] = value return socppi
def getsocpconstrmultipliers(cplex,dslack = None): socppi = dict() # Compute full dual slack (sum of dual multipliers for bound constraints # and per-constraint dual slacks) dense = dict(zip(cplex.variables.get_names(), cplex.solution.get_reduced_costs())) for n in cplex.quadratic_constraints.get_names(): v = cplex.solution.get_quadratic_dualslack(n) for (var,val) in zip(v.ind, v.val): dense[cplex.variables.get_names(var)] += val # Find the cone head variables and pick up the dual slacks for them. for n in cplex.quadratic_constraints.get_names(): q = cplex.quadratic_constraints.get_quadratic_components(n) for (i1,i2,v) in zip(q.ind1, q.ind2, q.val): if v < 0: name = cplex.variables.get_names(i1) socppi[n] = dense[name] break if dslack != None: dslack.clear() for key, value in six.iteritems(dense): dslack[key] = value return socppi
def checkkkt(c, cone, tol): # Read primal and dual solution information. x = dict(zip(c.variables.get_names(), c.solution.get_values())) s = dict( zip(c.linear_constraints.get_names(), c.solution.get_linear_slacks())) pi = dict( zip(c.linear_constraints.get_names(), c.solution.get_dual_values())) dslack = dict() for key, value in six.iteritems(getsocpconstrmultipliers(c, dslack)): pi[key] = value for (q, v) in zip( c.quadratic_constraints.get_names(), c.solution.get_quadratic_slacks( c.quadratic_constraints.get_names())): s[q] = v # Print out the data just fetched. print("x = [", end=' ') for n in c.variables.get_names(): print(" %7.3f" % x[n], end=' ') print(" ]") print("dslack = [", end=' ') for n in c.variables.get_names(): print(" %7.3f" % dslack[n], end=' ') print(" ]") print("pi = [", end=' ') for n in c.linear_constraints.get_names(): print(" %7.3f" % pi[n], end=' ') for n in c.quadratic_constraints.get_names(): print(" %7.3f" % pi[n], end=' ') print(" ]") print("slack = [", end=' ') for n in c.linear_constraints.get_names(): print(" %7.3f" % s[n], end=' ') for n in c.quadratic_constraints.get_names(): print(" %7.3f" % s[n], end=' ') print(" ]") # Test primal feasibility. # This example illustrates the use of dual vectors returned by CPLEX # to verify dual feasibility, so we do not test primal feasibility # here. # Test dual feasibility. # We must have # - for all <= constraints the respective pi value is non-negative, # - for all >= constraints the respective pi value is non-positive, # - the dslack value for all non-cone variables must be non-negative. # Note that we do not support ranged constraints here. for n in c.linear_constraints.get_names(): if c.linear_constraints.get_senses(n) == 'L' and pi[n] < -tol: print("Dual multiplier ", pi[n], " for <= constraint ", n, " not feasible.", file=sys.stderr) return False elif c.linear_constraints.get_senses(n) == 'G' and pi[n] > tol: print("Dual multiplier ", pi[n], " for >= constraint ", n, " not feasible.", file=sys.stderr) return False for n in c.quadratic_constraints.get_names(): if c.quadratic_constraints.get_senses(n) == 'L' and pi[n] < -tol: print("Dual multiplier ", pi[n], " for <= constraint ", n, " not feasible.", file=sys.stderr) return False elif c.quadratic_constraints.get_senses(n) == 'G' and pi[n] > tol: print("Dual multiplier ", pi[n], " for >= constraint ", n, " not feasible.", file=sys.stderr) return False for n in c.variables.get_names(): if cone[n] == NOT_IN_CONE and dslack[n] < -tol: print("Dual multiplier for ", n, " is not feasible: ", dslack[n], file=sys.stderr) return False # Test complementary slackness. # For each constraint either the constraint must have zero slack or # the dual multiplier for the constraint must be 0. We must also # consider the special case in which a variable is not explicitly # contained in a second order cone constraint. for n in c.linear_constraints.get_names(): if fabs(s[n]) > tol and fabs(pi[n]) > tol: print("Invalid complementary slackness for ", n, ": ", s[n], " and ", pi[n], file=sys.stderr) return False for n in c.quadratic_constraints.get_names(): if fabs(s[n]) > tol and fabs(pi[n]) > tol: print("Invalid complementary slackness for ", n, ": ", s[n], " and ", pi[n], file=sys.stderr) return False for n in c.variables.get_names(): if cone[n] == NOT_IN_CONE: if fabs(x[n]) > tol and fabs(dslack[n]) > tol: print("Invalid complementary slackness for ", n, ": ", x[n], " and ", dslack[n], file=sys.stderr) return False # Test stationarity. # We must have # c - g[i]'(X)*pi[i] = 0 # where c is the objective function, g[i] is the i-th constraint of the # problem, g[i]'(x) is the derivate of g[i] with respect to x and X is the # optimal solution. # We need to distinguish the following cases: # - linear constraints g(x) = ax - b. The derivative of such a # constraint is g'(x) = a. # - second order constraints g(x[1],...,x[n]) = -x[1] + |(x[2],...,x[n])| # the derivative of such a constraint is # g'(x) = (-1, x[2]/|(x[2],...,x[n])|, ..., x[n]/|(x[2],...,x[n])| # (here |.| denotes the Euclidean norm). # - bound constraints g(x) = -x for variables that are not explicitly # contained in any second order cone constraint. The derivative for # such a constraint is g'(x) = -1. # Note that it may happen that the derivative of a second order cone # constraint is not defined at the optimal solution X (this happens if # X=0). In this case we just skip the stationarity test. val = dict(zip(c.variables.get_names(), c.objective.get_linear())) for n in c.variables.get_names(): if cone[n] == NOT_IN_CONE: val[n] -= dslack[n] for n in c.linear_constraints.get_names(): r = c.linear_constraints.get_rows(n) for j in range(0, len(r.ind)): nj = c.variables.get_names(r.ind[j]) val[nj] -= r.val[j] * pi[n] for n in c.quadratic_constraints.get_names(): r = c.quadratic_constraints.get_quadratic_components(n) norm = 0 for j in range(0, len(r.ind1)): nj = c.variables.get_names(r.ind1[j]) if r.val[j] > 0: norm += x[nj] * x[nj] norm = sqrt(norm) if fabs(norm) <= tol: # Derivative is not defined. Skip test. print("Cannot test stationarity at non-differentiable point.", file=sys.stderr) return True for j in range(0, len(r.ind1)): nj = c.variables.get_names(r.ind1[j]) if r.val[j] < 0: val[nj] -= pi[n] else: val[nj] += pi[n] * x[nj] / norm # Now test that all elements in val[] are 0. for n in c.variables.get_names(): if fabs(val[n]) > tol: print("Invalid stationarity ", val[n], " for ", n, file=sys.stderr) return False return True
def checkkkt(c, cone, tol): # Read primal and dual solution information. x = dict(zip(c.variables.get_names(), c.solution.get_values())) s = dict(zip(c.linear_constraints.get_names(), c.solution.get_linear_slacks())) pi = dict(zip(c.linear_constraints.get_names(), c.solution.get_dual_values())) dslack = dict() for key,value in six.iteritems(getsocpconstrmultipliers(c, dslack)): pi[key] = value for (q,v) in zip(c.quadratic_constraints.get_names(), c.solution.get_quadratic_slacks(c.quadratic_constraints.get_names())): s[q] = v # Print out the data just fetched. print("x = [", end=' ') for n in c.variables.get_names(): print(" %7.3f" % x[n], end=' ') print(" ]") print("dslack = [", end=' ') for n in c.variables.get_names(): print(" %7.3f" % dslack[n], end=' ') print(" ]") print("pi = [", end=' ') for n in c.linear_constraints.get_names(): print(" %7.3f" % pi[n], end=' ') for n in c.quadratic_constraints.get_names(): print(" %7.3f" % pi[n], end=' ') print(" ]") print("slack = [", end=' ') for n in c.linear_constraints.get_names(): print(" %7.3f" % s[n], end=' ') for n in c.quadratic_constraints.get_names(): print(" %7.3f" % s[n], end=' ') print(" ]") # Test primal feasibility. # This example illustrates the use of dual vectors returned by CPLEX # to verify dual feasibility, so we do not test primal feasibility # here. # Test dual feasibility. # We must have # - for all <= constraints the respective pi value is non-negative, # - for all >= constraints the respective pi value is non-positive, # - the dslack value for all non-cone variables must be non-negative. # Note that we do not support ranged constraints here. for n in c.linear_constraints.get_names(): if c.linear_constraints.get_senses(n) == 'L' and pi[n] < -tol: print("Dual multiplier ", pi[n], " for <= constraint ", n, " not feasible.", file=sys.stderr) return False elif c.linear_constraints.get_senses(n) == 'G' and pi[n] > tol: print("Dual multiplier ", pi[n], " for >= constraint ", n, " not feasible.", file=sys.stderr) return False for n in c.quadratic_constraints.get_names(): if c.quadratic_constraints.get_senses(n) == 'L' and pi[n] < -tol: print("Dual multiplier ", pi[n], " for <= constraint ", n, " not feasible.", file=sys.stderr) return False elif c.quadratic_constraints.get_senses(n) == 'G' and pi[n] > tol: print("Dual multiplier ", pi[n], " for >= constraint ", n, " not feasible.", file=sys.stderr) return False for n in c.variables.get_names(): if cone[n] == NOT_IN_CONE and dslack[n] < -tol: print("Dual multiplier for ", n, " is not feasible: ", dslack[n], file=sys.stderr) return False # Test complementary slackness. # For each constraint either the constraint must have zero slack or # the dual multiplier for the constraint must be 0. We must also # consider the special case in which a variable is not explicitly # contained in a second order cone constraint. for n in c.linear_constraints.get_names(): if fabs(s[n]) > tol and fabs(pi[n]) > tol: print("Invalid complementary slackness for ", n, ": ", s[n], " and ", pi[n], file=sys.stderr) return False for n in c.quadratic_constraints.get_names(): if fabs(s[n]) > tol and fabs(pi[n]) > tol: print("Invalid complementary slackness for ", n, ": ", s[n], " and ", pi[n], file=sys.stderr) return False for n in c.variables.get_names(): if cone[n] == NOT_IN_CONE: if fabs(x[n]) > tol and fabs(dslack[n]) > tol: print("Invalid complementary slackness for ", n, ": ", x[n], " and ", dslack[n], file=sys.stderr) return False # Test stationarity. # We must have # c - g[i]'(X)*pi[i] = 0 # where c is the objective function, g[i] is the i-th constraint of the # problem, g[i]'(x) is the derivate of g[i] with respect to x and X is the # optimal solution. # We need to distinguish the following cases: # - linear constraints g(x) = ax - b. The derivative of such a # constraint is g'(x) = a. # - second order constraints g(x[1],...,x[n]) = -x[1] + |(x[2],...,x[n])| # the derivative of such a constraint is # g'(x) = (-1, x[2]/|(x[2],...,x[n])|, ..., x[n]/|(x[2],...,x[n])| # (here |.| denotes the Euclidean norm). # - bound constraints g(x) = -x for variables that are not explicitly # contained in any second order cone constraint. The derivative for # such a constraint is g'(x) = -1. # Note that it may happen that the derivative of a second order cone # constraint is not defined at the optimal solution X (this happens if # X=0). In this case we just skip the stationarity test. val = dict(zip(c.variables.get_names(), c.objective.get_linear())) for n in c.variables.get_names(): if cone[n] == NOT_IN_CONE: val[n] -= dslack[n] for n in c.linear_constraints.get_names(): r = c.linear_constraints.get_rows(n) for j in range(0, len(r.ind)): nj = c.variables.get_names(r.ind[j]) val[nj] -= r.val[j] * pi[n] for n in c.quadratic_constraints.get_names(): r = c.quadratic_constraints.get_quadratic_components(n) norm = 0 for j in range(0, len(r.ind1)): nj = c.variables.get_names(r.ind1[j]) if r.val[j] > 0: norm += x[nj] * x[nj] norm = sqrt(norm) if fabs(norm) <= tol: # Derivative is not defined. Skip test. print("Cannot test stationarity at non-differentiable point.", file=sys.stderr) return True for j in range(0, len(r.ind1)): nj = c.variables.get_names(r.ind1[j]) if r.val[j] < 0: val[nj] -= pi[n] else: val[nj] += pi[n] * x[nj] / norm # Now test that all elements in val[] are 0. for n in c.variables.get_names(): if fabs(val[n]) > tol: print("Invalid stationarity ", val[n], " for ", n, file=sys.stderr) return False return True