示例#1
0
def solve(A, rhs, ct=None, logLevel=0):
    s = CyClpSimplex()
    s.logLevel = logLevel
    lp_dim = A.shape[1]

    x = s.addVariable('x', lp_dim)
    A = np.matrix(A)
    rhs = CyLPArray(rhs)

    s += A * x >= rhs

    s += x[lp_dim - 1] >= 0
    s.objective = x[lp_dim - 1]
    nnz = np.count_nonzero(A)
    logging.debug(f"TASK SIZE XCOUNT: {lp_dim} GXCOUNT: {len(rhs)}")

    s.primal()
    k = list(s.primalConstraintSolution.keys())[0]
    k2 = list(s.dualConstraintSolution.keys())[0]
    q = s.dualConstraintSolution[k2]
    logging.debug(f"{s.getStatusString()} objective: {s.objectiveValue}")
    logging.debug(
        f"nonzeros rhs: {np.count_nonzero(s.primalConstraintSolution[k])}")
    logging.debug(
        f"nonzeros dual: {np.count_nonzero(s.dualConstraintSolution[k2])}")

    basis = s.getBasisStatus()
    print("Basis[0]")
    print(basis[0])
    print("basis[1]")
    print(basis[1])
    np.savetxt("out", basis[1])

    print("#" * 100)

    s = CyClpSimplex()
    s.logLevel = logLevel
    lp_dim = A.shape[1]

    x = s.addVariable('x', lp_dim)
    A = np.matrix(A)
    rhs = CyLPArray(rhs)

    s += A * x >= rhs

    s += x[lp_dim - 1] >= 0
    s.objective = x[lp_dim - 1]
    nnz = np.count_nonzero(A)
    logging.debug(f"TASK SIZE XCOUNT: {lp_dim} GXCOUNT: {len(rhs)}")

    s.setBasisStatus(*basis)
    s.primal()

    return s.primalVariableSolution['x']
示例#2
0
def solve(A, rhs, ct=None, logLevel=0, extnd=False, basis=False, mps_file=None):
    s = CyClpSimplex()
    s.logLevel = logLevel
    lp_dim = A.shape[1]

    x = s.addVariable('x', lp_dim)
    A = np.matrix(A)
    rhs = CyLPArray(rhs)

    s += A * x >= rhs

    s += x[lp_dim - 1] >= 0
    s.objective = x[lp_dim - 1]
    nnz = np.count_nonzero(A)
    if not mps_file is None:
        s.writeMps(mps_file)
        return None
    logging.debug(f"TASK SIZE XCOUNT: {lp_dim} GXCOUNT: {len(rhs)}")

    s.primal()
    k = list(s.primalConstraintSolution.keys())[0]
    k2 =list(s.dualConstraintSolution.keys())[0]
    q = s.dualConstraintSolution[k2]
    logging.debug(f"{s.getStatusString()} objective: {s.objectiveValue}")
    logging.debug(f"nonzeros rhs: {np.count_nonzero(s.primalConstraintSolution[k])}")
    logging.debug(f"nonzeros dual: {np.count_nonzero(s.dualConstraintSolution[k2])}")

    if extnd and not basis:
        return s.primalVariableSolution['x'],s.primalConstraintSolution[k],s.dualConstraintSolution[k2]
    elif not extnd and basis:
        basis = s.getBasisStatus()
        return s.primalVariableSolution['x'],*basis
    else:
        return s.primalVariableSolution['x']
def classical_exactcover_solver(A, w=None, num_threads=4):
    nrows, ncolumns = np.shape(A)
    if w is None:
        w = np.ones(ncolumns)
    assert(len(w) == ncolumns)
    assert(sum(w >= 0))
    model = CyLPModel()
    # Decision variables, one for each cover
    x = model.addVariable('x', ncolumns, isInt=True)
    # Adding the box contraints
    model += 0 <= x <= 1
    # Adding the cover constraints
    # Sum_j x_ij ==  1
    for i in range(nrows):
        model += CyLPArray(A[i,:]) * x == 1
    # Adding the objective function
    model.objective = CyLPArray(w) * x
    lp = CyClpSimplex(model)
    lp.logLevel = 0
    lp.optimizationDirection = 'min'
    mip = lp.getCbcModel()
    mip.logLevel = 0
    # Setting number of threads
    mip.numberThreads = num_threads
    mip.solve()

    return mip.objectiveValue, [int(i) for i in mip.primalVariableSolution['x']]
示例#4
0
 def __init__(self: T,
              lp: CyClpSimplex,
              integerIndices: List[int],
              lower_bound: Union[float, int] = -float('inf'),
              b_idx: int = None,
              b_dir: str = None,
              b_val: float = None,
              depth=0):
     """
     :param lp: model object simplex is run against
     :param integerIndices: indices of variables we aim to find integer solutions
     :param lower_bound: starting lower bound on optimal objective value
     for the minimization problem in this node
     :param b_idx: index of the branching variable
     :param b_dir: direction of branching
     :param b_val: initial value of the branching variable
     :param depth: how deep in the tree this node is
     """
     assert isinstance(lp, CyClpSimplex), 'lp must be CyClpSimplex instance'
     assert all(0 <= idx < lp.nVariables and isinstance(idx, int)
                for idx in integerIndices), 'indices must match variables'
     assert len(set(integerIndices)) == len(integerIndices), \
         'indices must be distinct'
     assert isinstance(lower_bound, float) or isinstance(lower_bound, int), \
         'lower bound must be a float or an int'
     assert (b_dir is None) == (b_idx is None) == (b_val is None), \
         'none are none or all are none'
     assert b_idx in integerIndices or b_idx is None, \
         'branch index corresponds to integer variable if it exists'
     assert b_dir in ['up', 'down'] or b_dir is None, \
         'we can only round a variable up or down when branching'
     if b_val is not None:
         good_down = 0 < b_val - lp.variablesUpper[b_idx] < 1
         good_up = 0 < lp.variablesLower[b_idx] - b_val < 1
         assert (b_dir == 'down' and good_down) or \
                (b_dir == 'up' and good_up), 'branch val should be within 1 of both bounds'
     assert isinstance(depth,
                       int) and depth >= 0, 'depth is a positive integer'
     lp.logLevel = 0
     self._lp = lp
     self._integerIndices = integerIndices
     self.lower_bound = lower_bound
     self.objective_value = None
     self.solution = None
     self.lp_feasible = None
     self.unbounded = None
     self.mip_feasible = None
     self._epsilon = .0001
     self._b_dir = b_dir
     self._b_idx = b_idx
     self._b_val = b_val
     self.depth = depth
     self.search_method = 'best first'
     self.branch_method = 'most fractional'
def branch_and_bound(G, num_threads=4):
    N = len(G)
    model = CyLPModel()
    # Decision variables, one for each node
    x = model.addVariable('x', N, isInt=True)
    # Adjacency matrix (possibly weighted)
    W = nx.to_numpy_matrix(G)
    z_ind = dict()
    ind = 0
    w = []
    for i in range(N):
        j_range = range(N)
        if (not nx.is_directed(G)):
            # Reduced range for undirected graphs
            j_range = range(i, N)
        for j in j_range:
            if (W[i,j] == 0):
                continue
            if (i not in z_ind):
                z_ind[i] = dict()  
            z_ind[i][j] = ind
            w.append(W[i,j])
            ind += 1
    # Aux variables, one for each edge
    z = model.addVariable('z', len(w), isInt=True)
    # Adding the box contraints
    model += 0 <= x <= 1
    model += 0 <= z <= 1
    # Adding the cutting constraints
    # If x_i == x_j then z_ij = 0
    # If x_i != x_j then z_ij = 1
    for i in z_ind:
        for j in z_ind[i]:
            model += z[z_ind[i][j]] - x[i] - x[j] <= 0
            model += z[z_ind[i][j]] + x[i] + x[j] <= 2
    # Adding the objective function
    model.objective = CyLPArray(w) * z
    lp = CyClpSimplex(model)
    lp.logLevel = 0
    lp.optimizationDirection = 'max'
    mip = lp.getCbcModel()
    mip.logLevel = 0
    # Setting number of threads
    mip.numberThreads = num_threads
    mip.solve()

    return mip.objectiveValue, [int(i) for i in mip.primalVariableSolution['x']]
def computePriceSweep(thisSlice,chunkNum, qpid, qresult):
	myLength = thisSlice.shape[1]

	myPID = multiprocessing.current_process().pid

	# Add our process id to the list of process ids
	while qpid.empty():
		time.sleep(0.01)
	pidList = qpid.get()
	pidList.append(myPID)
	qpid.put(pidList)

	storagePriceSet = np.arange(1.0,20.1,0.25)
	storagePriceSet = np.arange(1.0,3.1,1)
	eff_round = 0.9  # Round-trip efficiency
	E_min = 0
	E_max = 1

	# Endogenous parameters; calculated automatically
	(eff_in, eff_out) = [np.sqrt(eff_round)] *2  # Properly account for the round trip efficiency of storage
	P_max = E_max/eff_in # Max discharge power at grid intertie, e.g max limit for C_i
	P_min = -1*E_max/eff_out # Max charge power at grid intertie, e.g. min D_i

	# Create a set of zero-filled dataframes for storing results
	resultIndex = pd.MultiIndex.from_product([thisSlice.index,['size','kwhPassed','profit']])
	results = pd.DataFrame(index = resultIndex, columns=storagePriceSet)

	# Create clean problem matrices - needs efficiency and length!
	(A, b, A_eq, b_eq) = createABMatrices(myLength, delta_T, eff_in, eff_out, P_min, P_max, E_min, E_max)
	# Define model:
	coolStart = CyClpSimplex()
	coolStart.logLevel = 0
	x_var = coolStart.addVariable('x',myLength*3+2)
	# Add constraints to model:
	coolStart += A * x_var <= b.toarray()
	coolStart += A_eq * x_var == b_eq.toarray()


	newIDs = [] # this holds the names of nodes which we've recently processed

	def dumpResults():
		results.dropna(axis=0,how='all').to_csv('Data/priceSweepResults_pid'+str(myPID)+'temp.csv' )

		# Make sure that the results queue hasn't been checked out by somebody else
		while qresult.empty():
			time.sleep(0.01)
		resultList = qresult.get()

		resultList[chunkNum] = resultList[chunkNum] + newIDs
		qresult.put(resultList)

	for i in range(thisSlice.shape[0]):
		## Set up prices
		myNodeName = thisSlice.index[i]
		energyPrice = thisSlice.loc[myNodeName,:] / 1000.0 # Price $/kWh as array

		# if (np.random.random(1)[0] < 0.05):
		# 	sys.exit(1) # Randomly kill the process

		c = np.concatenate([[0.0],[0.0]*(myLength+1),energyPrice,energyPrice],axis=0)  #placeholder; No cost for storage state; charged for what we consume, get paid for what we discharge
		#[[storagePricePlaceholder],[0]*(myLength+1),myPrice,myPrice],axis=1)
		c_clp = CyLPArray(c)

		sweepStartTime = time.time()

		for myStoragePrice in storagePriceSet:
			c_clp[0] = myStoragePrice * simulationYears
			coolStart.objective = c_clp * x_var

			# Run the model
			coolStart.primal()

			# Results- Rows are Nodes, indexed by name. Columns are Storage price, indexed by price
			x_out = coolStart.primalVariableSolution['x']

			results.loc[(myNodeName,'size'),     myStoragePrice] = x_out[0]
			results.loc[(myNodeName,'profit'),   myStoragePrice] = np.dot(-c, x_out)
			results.loc[(myNodeName,'kwhPassed'),myStoragePrice] = sum(x_out[2+myLength : 2+myLength*2]) * eff_in # Note: this is the net power pulled from the grid, not the number of cycles when the system is unconstrained

		storagePriceSet = storagePriceSet[::-1] # Reverse the price set so that we start from the same price for the next node to make warm-start more effective

		newIDs.append(myNodeName)

		if (i+1)%5==0:
			dumpResults()  # Write the results to file, and then also update the process Queue with the 
			newIDs = []

	# The results should now be all done!
	dumpResults()
示例#7
0
    def solve(self, objective, constraints, cached_data,
              warm_start, verbose, solver_opts):
        """Returns the result of the call to the solver.

        Parameters
        ----------
        objective : LinOp
            The canonicalized objective.
        constraints : list
            The list of canonicalized cosntraints.
        cached_data : dict
            A map of solver name to cached problem data.
        warm_start : bool
            Not used.
        verbose : bool
            Should the solver print output?
        solver_opts : dict
            Additional arguments for the solver.

        Returns
        -------
        tuple
            (status, optimal value, primal, equality dual, inequality dual)
        """
        # Import basic modelling tools of cylp
        from cylp.cy import CyClpSimplex
        from cylp.py.modeling.CyLPModel import CyLPArray

        # Get problem data
        data = self.get_problem_data(objective, constraints, cached_data)

        c = data[s.C]
        b = data[s.B]
        A = data[s.A]
        dims = data[s.DIMS]

        n = c.shape[0]

        solver_cache = cached_data[self.name()]

        # Problem
        model = CyClpSimplex()

        # Variables
        x = model.addVariable('x', n)

        if self.is_mip(data):
            for i in data[s.BOOL_IDX]:
                model.setInteger(x[i])
            for i in data[s.INT_IDX]:
                model.setInteger(x[i])

        # Constraints
        # eq
        model += A[0:dims[s.EQ_DIM], :] * x == b[0:dims[s.EQ_DIM]]

        # leq
        leq_start = dims[s.EQ_DIM]
        leq_end = dims[s.EQ_DIM] + dims[s.LEQ_DIM]
        model += A[leq_start:leq_end, :] * x <= b[leq_start:leq_end]

        # no boolean vars available in cbc -> model as int + restrict to [0,1]
        if self.is_mip(data):
            for i in data[s.BOOL_IDX]:
                model += 0 <= x[i] <= 1

        # Objective
        model.objective = c

        # Build model & solve
        status = None
        if self.is_mip(data):
            cbcModel = model.getCbcModel()  # need to convert model
            if not verbose:
                cbcModel.logLevel = 0

            # Add cut-generators (optional)
            for cut_name, cut_func in six.iteritems(self.SUPPORTED_CUT_GENERATORS):
                if cut_name in solver_opts and solver_opts[cut_name]:
                    module = importlib.import_module("cylp.cy.CyCgl")
                    funcToCall = getattr(module, cut_func)
                    cut_gen = funcToCall()
                    cbcModel.addCutGenerator(cut_gen, name=cut_name)

            # solve
            status = cbcModel.branchAndBound()
        else:
            if not verbose:
                model.logLevel = 0
            status = model.primal()  # solve

        results_dict = {}
        results_dict["status"] = status

        if self.is_mip(data):
            results_dict["x"] = cbcModel.primalVariableSolution['x']
            results_dict["obj_value"] = cbcModel.objectiveValue
        else:
            results_dict["x"] = model.primalVariableSolution['x']
            results_dict["obj_value"] = model.objectiveValue

        return self.format_results(results_dict, data, cached_data)
 
     x = lp.addVariable('x', LP.numVars)
         
     if LP.sense[0] == '>=':
         lp += A * x >= b
     else:
         lp += A * x <= b
     #lp += x >= 0
 
     c = CyLPArray(LP.c)
     # We are maximizing, so negate objective
     if LP.sense[1] == 'Min':
         lp.objective = c * x
     else:
         lp.objective = -c * x
     lp.logLevel = 0
     lp.primal(startFinishOptions = 'x')
     np.set_printoptions(precision = 2, linewidth = 200)
     print('Basic variables: ', lp.basicVariables)
     print("Current tableaux and reduced costs:")
     print(lp.reducedCosts)
     print(np.around(lp.tableau, decimals = 3))
     print('Right-hand side of optimal tableaux:')
     #There is a bug in CyLP and this is wrong
     #print lp.rhs
     if LP.sense[0] == '<=':
         print(np.dot(lp.basisInverse, lp.constraintsUpper))
     else:
         print(np.dot(lp.basisInverse, lp.constraintsLower))
     print('Inverse of optimal basis:')
     print(np.around(lp.basisInverse, 3))
示例#9
0
def disjunctionToCut(lp, pi, pi0, integerIndices = None, sense = '>=',
                       sol = None, debug_print = False, use_cylp = True):

    me = "cglp_cuts: "

    if sol is None:
        sol = lp.primalVariableSolution['x']
    infinity = lp.getCoinInfinity()

    if debug_print:
        print(me, "constraints sense = ", sense)
        print(me, "con lower bounds = ", lp.constraintsLower)
        print(me, "con upper bounds = ", lp.constraintsUpper)
        print(me, "con matrix = ", lp.coefMatrix.toarray())
        print(me, "vars lower bounds = ", lp.variablesLower)
        print(me, "vars upper bounds = ", lp.variablesUpper)
        print(me, "Assuming objective is to minimize")
        print(me, "objective = ", lp.objective)
        print(me, "infinity = ", infinity)
        print(me, "current point = ", sol)
        print(me, "pi = ", pi)
        print(me, "pi0 = ", pi0)

    A = lp.coefMatrix.toarray()
    #c = lp.objective
    ## Convert to >= if the problem is in <= form.
    if sense == '<=':
        b = deepcopy(lp.constraintsUpper)
        b = -1.0*b
        A = -1.0*A
    else:
        b = deepcopy(lp.constraintsLower)

    #Add bounds on variables as explicit constraints
    for i in range(lp.nCols):
        e = np.zeros((1, lp.nCols))
        if lp.variablesUpper[i] < infinity:
            b.resize(b.size+1, refcheck = False)
            e[0, i] = -1.0
            b[-1] = -1.0*lp.variablesUpper[i]
            A = np.vstack((A, e))
        if lp.variablesLower[i] > -infinity:
            b.resize(b.size+1, refcheck = False)
            e[0, i] = 1.0
            b[-1] = lp.variablesLower[i]
            A = np.vstack((A, e))
    A = csc_matrixPlus(A)

    ############################################################################
    ## There are two given LPs:
    ## s.t. Ax >= b           s.t. Ax >= b
    ##   -pi.x >= -pi_0          pi.x >= pi_0+1
    ## A, b, c, pi, pi_0 are given
    ##
    ## CGLP: alpha.x >= beta should be valid for both LPs above
    ##
    ## min alpha.x* - beta
    ## uA - u0.pi = alpha
    ## vA + v0.pi = alpha
    ## ub - u0.pi_0 >= beta 
    ## vb + v0.(pi_0 + 1) >= beta 
    ## u0 + v0 = 1
    ## u, v, u0, v0 >= 0
    ## if min value comes out < 0, then (alpha.x >= beta) is a cut.
    ############################################################################

    b = CyLPArray(b)
    pi = CyLPArray(pi)
    
    Atran = A.transpose()

    if use_cylp:
        sp = CyLPModel()
        u = sp.addVariable('u', A.shape[0], isInt = False)
        v = sp.addVariable('v', A.shape[0], isInt = False)
        u0 = sp.addVariable('u0', 1, isInt = False)
        v0 = sp.addVariable('v0', 1, isInt = False)
        alpha = sp.addVariable('alpha', lp.nVariables, isInt = False)
        beta = sp.addVariable('beta', 1, isInt = False)
    
        for i in range(A.shape[1]):
            sp += alpha[i] - sum(Atran[i,j]*u[j] for j in range(A.shape[0])) + pi[i]*u0 == 0
        for i in range(A.shape[1]):
            sp += alpha[i] - sum(Atran[i,j]*v[j] for j in range(A.shape[0])) - pi[i]*v0 == 0
        sp += beta - b*u + pi0*u0 <= 0
        sp += beta - b*v - (pi0 + 1)*v0 <= 0
        sp += u0 + v0 == 1
        if sense == '<=':
            sp += u >= 0
            sp += v >= 0
            sp += u0 >= 0
            sp += v0 >= 0
        else:
            #TODO this direction is not debugged
            # Is this all we need?
            sp += u <= 0
            sp += v <= 0
            sp += u0 <= 0
            sp += v0 <= 0
        sp.objective = sum(sol[i]*alpha[i] for i in range(A.shape[1])) - beta
        cbcModel = CyClpSimplex(sp).getCbcModel()
        cbcModel.logLevel = 0
        #cbcModel.maximumSeconds = 5
        cbcModel.solve()
        beta = cbcModel.primalVariableSolution['beta'][0]
        alpha = cbcModel.primalVariableSolution['alpha']
        u = cbcModel.primalVariableSolution['u']
        v = cbcModel.primalVariableSolution['v']
        u0 = cbcModel.primalVariableSolution['u0'][0]
        v0 = cbcModel.primalVariableSolution['v0'][0]
        if debug_print:
            print('Objective Value: ', cbcModel.objectiveValue)
            print('alpha: ', alpha, 'alpha*sol: ', np.dot(alpha, sol))
            print('beta: ', beta)
            print('Violation of cut: ',  np.dot(alpha, sol) - beta)
    else: 
        CG = AbstractModel()
        CG.u = Var(list(range(A.shape[0])), domain=NonNegativeReals,
                   bounds = (0.0, None))
        CG.v = Var(list(range(A.shape[0])), domain=NonNegativeReals,
                   bounds = (0.0, None))
        CG.u0 = Var(domain=NonNegativeReals, bounds = (0.0, None))
        CG.v0 = Var(domain=NonNegativeReals, bounds = (0.0, None))
        CG.alpha = Var(list(range(A.shape[0])), domain=Reals,
                       bounds = (None, None))    
        CG.beta  = Var(domain=Reals, bounds = (None, None))    
        
        ## Constraints
        def pi_rule_left(CG, i):
            x = float(pi[i])
            return(sum(Atran[i, j]*CG.u[j] for j in range(A.shape[0])) -
                   x*CG.u0 - CG.alpha[i] == 0.0)
        CG.pi_rule_left = Constraint(list(range(A.shape[1])), rule=pi_rule_left)
        
        def pi_rule_right(CG, i):
            x = float(pi[i])
            return(sum(Atran[i, j]*CG.v[j] for j in range(A.shape[0])) +
                   x*CG.v0 - CG.alpha[i] == 0.0)
        CG.pi_rule_right = Constraint(list(range(A.shape[1])), rule=pi_rule_right)
        
        def pi0_rule_left(CG):
            return(sum(b[j]*CG.u[j] for j in range(A.shape[0])) -
                   pi0*CG.u0 - CG.beta >= 0.0)
        CG.pi0_rule_left = Constraint(rule=pi0_rule_left)
        
        def pi0_rule_right(CG):
            return(sum(b[j]*CG.v[j] for j in range(A.shape[0])) +
                   (pi0 + 1)*CG.v0 - CG.beta >= 0.0)
        CG.pi0_rule_right = Constraint(rule=pi0_rule_right)
        
        def normalization_rule(CG):
            return(CG.u0 + CG.v0 == 1.0)
        CG.normalization_rule = Constraint(rule=normalization_rule)
        
        def objective_rule(CG):
            return(sum(sol[i]*CG.alpha[i] for i in range(A.shape[1])) -
                   CG.beta)
        CG.objective = Objective(sense=minimize, rule=objective_rule)
        
        opt = SolverFactory("cbc")
        instance = CG.create_instance()
        #instance.pprint()
        #instance.write("foo.nl", format = "nl")
        #opt.options['bonmin.bb_log_level'] = 5
        #opt.options['bonmin.bb_log_interval'] = 1
        results = opt.solve(instance, tee=False)
        #results = opt.solve(instance)
        instance.solutions.load_from(results)
        
        beta = instance.beta.value
        alpha = np.array([instance.alpha[i].value
                          for i in range(lp.nVariables)])
    violation =  beta - np.dot(alpha, sol) 
    if debug_print:
        print(me, 'Beta: ', beta)
        print(me, 'alpha: ', alpha)
        print(me, 'Violation of cut: ', violation)
        
    if violation > 0.001:
        if (sense == ">="):
            return [(alpha, beta)]
        else:
            return [(-alpha, -beta)]
    return []
        x = lp.addVariable('x', LP.numVars)

        if LP.sense[0] == '>=':
            lp += A * x >= b
        else:
            lp += A * x <= b
        #lp += x >= 0

        c = CyLPArray(LP.c)
        # We are maximizing, so negate objective
        if LP.sense[1] == 'Min':
            lp.objective = c * x
        else:
            lp.objective = -c * x
        lp.logLevel = 0
        lp.primal(startFinishOptions='x')
        np.set_printoptions(precision=2, linewidth=200)
        print 'Basic variables: ', lp.basicVariables
        print "Current tableaux and reduced costs:"
        print lp.reducedCosts
        print np.around(lp.tableau, decimals=3)
        print 'Right-hand side of optimal tableaux:'
        #There is a bug in CyLP and this is wrong
        #print lp.rhs
        if LP.sense[0] == '<=':
            print np.dot(lp.basisInverse, lp.constraintsUpper)
        else:
            print np.dot(lp.basisInverse, lp.constraintsLower)
        print 'Inverse of optimal basis:'
        print np.around(lp.basisInverse, 3)
示例#11
0
def maxViolationSplitCuts(lp, integerIndices = None, sense = '>=', sol = None,
              max_coeff = 1):
    #Warning: At the moment, you must put bound constraints in explicitly for split cuts
    A = lp.coefMatrix
    if sense == '<=':
        b = CyLPArray(lp.constraintsUpper)
    else:
        b = CyLPArray(lp.constraintsLower)
    if integerIndices is None:
        integerIndices = range(lp.nVariables)
    if sol is None:
        sol = lp.primalVariableSolution['x']
    s = A*sol - b
    best = lp.getCoinInfinity()
    best_theta = None

    for theta in [0.01, 0.02, 0.03, 0.04, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5]:
        sp = CyLPModel()
        u = sp.addVariable('u', lp.nConstraints, isInt = False)
        v = sp.addVariable('v', lp.nConstraints, isInt = False)
        pi = sp.addVariable('pi', lp.nVariables, isInt = True)
        pi0 = sp.addVariable('pi0', 1, isInt = True)
    
        sp += pi + A.transpose()*u - A.transpose()*v == 0
        sp += pi0 + b*u - b*v == theta - 1
        if sense == '<=':
            sp += u >= 0
            sp += v >= 0
        else:
            #TODO this direction is not debugged
            # Is this all we need?
            sp += u <= 0
            sp += v <= 0
            
        sp.objective = (theta-1)*s*u - theta*s*v
        for i in xrange(lp.nVariables):
            if i in integerIndices:
                sp += -max_coeff <= pi[i] <= max_coeff
            else:
                sp[i] += pi[i] == 0

        cbcModel = CyClpSimplex(sp).getCbcModel()
        cbcModel.logLevel = 0
        #cbcModel.maximumSeconds = 5
        cbcModel.solve()
        if debug_print:
            #print 'Theta: ', theta, 
            #print 'Objective Value: ', cbcModel.objectiveValue - theta*(1-theta)
            #print 'pi: ', cbcModel.primalVariableSolution['pi']
            #print 'pi0: ', cbcModel.primalVariableSolution['pi0']
            multu = cbcModel.primalVariableSolution['u']
            disjunction = cbcModel.primalVariableSolution['pi']
            rhs = cbcModel.primalVariableSolution['pi0']
            alpha = A.transpose()*multu + theta*disjunction
            beta = np.dot(b, multu) + theta*rhs
            #print 'alpha: ', alpha, 'alpha*sol: ', np.dot(alpha, sol)
            #print 'beta: ', beta
            #print 'Violation of cut: ',  np.dot(alpha, sol) - beta
        if cbcModel.objectiveValue - theta*(1-theta) < best:
            best = cbcModel.objectiveValue - theta*(1-theta)
            best_multu = cbcModel.primalVariableSolution['u']
            best_multv = cbcModel.primalVariableSolution['v']
            best_disjunction = cbcModel.primalVariableSolution['pi']
            best_rhs = cbcModel.primalVariableSolution['pi0']
            best_theta = theta
            
    if best_theta is not None:
        alpha = A.transpose()*best_multu + best_theta*best_disjunction
        beta = np.dot(b, best_multu) + best_theta*best_rhs
        if debug_print:
            print 'Violation of cut: ',  np.dot(alpha, sol) - beta
            print 'pi: ', best_disjunction
            print 'pi0: ', best_rhs
            print 'theta: ',  best_theta
        if (abs(alpha) > 1e-6).any():
            return [(alpha, beta)] 
    return []
def classical_maxkcut_solver(G, num_partitions, num_threads=4):
    # G: NetworkX graph
    # num_partitions: the number partitions or groups in which we should
    #                 subdivide the nodes (i.e., the value of K)

    N = len(G)
    model = CyLPModel()
    # Decision variables, one for each node
    x = model.addVariable('x', num_partitions * N, isInt=True)
    # Adjacency matrix (possibly weighted)
    W = nx.to_numpy_matrix(G)
    z_ind = dict()
    ind = 0
    w = []
    for i in range(N):
        j_range = range(N)
        if (not nx.is_directed(G)):
            # Reduced range for undirected graphs
            j_range = range(i, N)
        for j in j_range:
            if (W[i, j] == 0):
                continue
            if (i not in z_ind):
                z_ind[i] = dict()
            z_ind[i][j] = ind
            w.append(W[i, j])
            ind += 1
    # Aux variables, one for each edge
    z = model.addVariable('z', len(w), isInt=True)
    # Adding the box contraints
    model += 0 <= x <= 1
    model += 0 <= z <= 1
    # Adding the selection constraints
    for i in range(N):
        indices = [i + k * N for k in range(num_partitions)]
        model += x[indices].sum() == 1
    # Adding the cutting constraints
    for i in z_ind:
        for j in z_ind[i]:
            for k in range(num_partitions):
                shift = k * N
                model += z[z_ind[i][j]] + x[i + shift] + x[j + shift] <= 2
                model += z[z_ind[i][j]] + x[i + shift] - x[j + shift] >= 0
                model += z[z_ind[i][j]] - x[i + shift] + x[j + shift] >= 0
    # Adding the objective function
    model.objective = CyLPArray(w) * z
    lp = CyClpSimplex(model)
    lp.logLevel = 0
    lp.optimizationDirection = 'max'
    mip = lp.getCbcModel()
    mip.logLevel = 0
    # Setting number of threads
    mip.numberThreads = num_threads
    mip.solve()
    sol = [int(i) for i in mip.primalVariableSolution['x']]
    sol_formatted = []
    for i in range(N):
        indices = [i + k * N for k in range(num_partitions)]
        for j in range(num_partitions):
            if (sol[indices[j]] == 1):
                sol_formatted.append(j)
                break

    assert (len(sol_formatted) == N)

    return mip.objectiveValue, sol_formatted
示例#13
0
def computePriceSweep(thisSlice):
    ###### BEGINNING OF MULTIPROCESSING FUNCTION ###########
    myLength = thisSlice.shape[1]

    # Simulation parameters - set these!
    storagePriceSet = np.arange(1.0,20.1,0.25)
#    storagePriceSet = np.arange(1.0,3.1,1)
    eff_round = 0.9  # Round-trip efficiency
    E_min = 0
    E_max = 1

    # Endogenous parameters; calculated automatically
    (eff_in, eff_out) = [np.sqrt(eff_round)] *2  # Properly account for the round trip efficiency of storage
    P_max = E_max/eff_in # Max discharge power at grid intertie, e.g max limit for C_i
    P_min = -1*E_max/eff_out # Max charge power at grid intertie, e.g. min D_i

    # Create a set of zero-filled dataframes for storing results
    resultIndex = pd.MultiIndex.from_product([thisSlice.index,['size','kwhPassed','profit']])
    results = pd.DataFrame(index = resultIndex, columns=storagePriceSet)

    # Create clean problem matrices - needs efficiency and length!
    (A, b, A_eq, b_eq) = createABMatrices(myLength, delta_T, eff_in, eff_out, P_min, P_max, E_min, E_max)
    # Define model:
    coolStart = CyClpSimplex()
    coolStart.logLevel = 0
    x_var = coolStart.addVariable('x',myLength*3+2)
    # Add constraints to model:
    coolStart += A * x_var <= b.toarray()
    coolStart += A_eq * x_var == b_eq.toarray()
    # print("Finished with problem setup")
    # sys.stdout.flush()

    # everythingStarts = time.time()
    # startTime = time.time()

    for myNodeName in thisSlice.index:
        ## Set up prices
    #     myNodeName = thisSlice.index[i]
        energyPrice = thisSlice.loc[myNodeName,:] / 1000.0 # Price $/kWh as array

        c = np.concatenate([[0.0],[0.0]*(myLength+1),energyPrice,energyPrice],axis=0)  #placeholder; No cost for storage state; charged for what we consume, get paid for what we discharge
        #[[storagePricePlaceholder],[0]*(myLength+1),myPrice,myPrice],axis=1)
        c_clp = CyLPArray(c)

        sweepStartTime = time.time()

        for myStoragePrice in storagePriceSet:
            c_clp[0] = myStoragePrice * simulationYears
            coolStart.objective = c_clp * x_var

            # Run the model
            coolStart.primal()

            # Results- Rows are Nodes, indexed by name. Columns are Storage price, indexed by price
            x_out = coolStart.primalVariableSolution['x']
            results.loc[(myNodeName,'size'),     myStoragePrice] = x_out[0]
            results.loc[(myNodeName,'profit'),   myStoragePrice] = np.dot(-c, x_out)
            results.loc[(myNodeName,'kwhPassed'),myStoragePrice] = sum(x_out[2+myLength : 2+myLength*2]) * eff_in # Note: this is the net power pulled from the grid, not the number of cycles when the system is unconstrained

        storagePriceSet = storagePriceSet[::-1] # Reverse the price set so that we start from the same price for the next node to make warm-start more effective

    #     if ((i+1) % reportFrequency == 0): # Save our progress along the way
    #         elapsedTime = time.time()-startTime
    #         print("Finished node %s; \t%s computations in \t%.4f s \t(%.4f s/solve)" 
    #               % (i, scenariosPerReport,elapsedTime,elapsedTime/scenariosPerReport))
    #         sys.stdout.flush()
    #         sizeDf.to_csv('Data/VaryingPrices_StorageSizing_v2.csv')
    #         profitDf.to_csv('Data/VaryingPrices_StorageProfits_v2.csv')
    #         cycleDf.to_csv('Data/VaryingPrices_StorageCycles_v2.csv')

    # print("Done in %.3f s"%(time.time()-everythingStarts))
    return results
示例#14
0
文件: cbc_intf.py 项目: wolfws/cvxpy
    def solve(self, objective, constraints, cached_data, warm_start, verbose,
              solver_opts):
        """Returns the result of the call to the solver.

        Parameters
        ----------
        objective : LinOp
            The canonicalized objective.
        constraints : list
            The list of canonicalized cosntraints.
        cached_data : dict
            A map of solver name to cached problem data.
        warm_start : bool
            Not used.
        verbose : bool
            Should the solver print output?
        solver_opts : dict
            Additional arguments for the solver.

        Returns
        -------
        tuple
            (status, optimal value, primal, equality dual, inequality dual)
        """
        # Import basic modelling tools of cylp
        from cylp.cy import CyClpSimplex

        # Get problem data
        data = self.get_problem_data(objective, constraints, cached_data)

        c = data[s.C]
        b = data[s.B]
        A = data[s.A]
        dims = data[s.DIMS]

        n = c.shape[0]

        # Problem
        model = CyClpSimplex()

        # Variables
        x = model.addVariable('x', n)

        if self.is_mip(data):
            for i in data[s.BOOL_IDX]:
                model.setInteger(x[i])
            for i in data[s.INT_IDX]:
                model.setInteger(x[i])

        # Constraints
        # eq
        model += A[0:dims[s.EQ_DIM], :] * x == b[0:dims[s.EQ_DIM]]

        # leq
        leq_start = dims[s.EQ_DIM]
        leq_end = dims[s.EQ_DIM] + dims[s.LEQ_DIM]
        model += A[leq_start:leq_end, :] * x <= b[leq_start:leq_end]

        # no boolean vars available in cbc -> model as int + restrict to [0,1]
        if self.is_mip(data):
            for i in data[s.BOOL_IDX]:
                model += 0 <= x[i] <= 1

        # Objective
        model.objective = c

        # Build model & solve
        status = None
        if self.is_mip(data):
            cbcModel = model.getCbcModel()  # need to convert model
            if not verbose:
                cbcModel.logLevel = 0

            # Add cut-generators (optional)
            for cut_name, cut_func in six.iteritems(
                    self.SUPPORTED_CUT_GENERATORS):
                if cut_name in solver_opts and solver_opts[cut_name]:
                    module = importlib.import_module("cylp.cy.CyCgl")
                    funcToCall = getattr(module, cut_func)
                    cut_gen = funcToCall()
                    cbcModel.addCutGenerator(cut_gen, name=cut_name)

            # solve
            status = cbcModel.branchAndBound()
        else:
            if not verbose:
                model.logLevel = 0
            status = model.primal()  # solve

        results_dict = {}
        results_dict["status"] = status

        if self.is_mip(data):
            results_dict["x"] = cbcModel.primalVariableSolution['x']
            results_dict["obj_value"] = cbcModel.objectiveValue
        else:
            results_dict["x"] = model.primalVariableSolution['x']
            results_dict["obj_value"] = model.objectiveValue

        return self.format_results(results_dict, data, cached_data)
示例#15
0
def disjunctionToCut(m, pi, pi0, debug_print=False, use_cylp=True, eps=EPS):
    '''Generate the most violated valid inequality from a given disjunction'''
    me = "cglp_cuts: "
    lp = m.lp
    sol = lp.primalVariableSolution['x']

    if debug_print:
        print(me, "constraints sense = ", m.sense)
        print(me, "matrix = ")
        print(m.A)
        print(me, "rhs = ", m.b)
        print(me, "vars lower bounds = ", lp.variablesLower)
        print(me, "vars upper bounds = ", lp.variablesUpper)
        print(me, "objective = ", lp.objective)
        print(me, "current solution = ", sol)
        print(me, "pi = ", pi)
        print(me, "pi0 = ", pi0)

    ############################################################################
    ## There are two given LPs:
    ## s.t. Ax >= b           s.t. Ax >= b
    ##   -pi.x >= -pi_0          pi.x >= pi_0+1
    ## A, b, c, pi, pi_0 are given
    ##
    ## CGLP: alpha.x >= beta should be valid for both LPs above
    ##
    ## min alpha.x* - beta
    ## uA - u0.pi = alpha
    ## vA + v0.pi = alpha
    ## ub - u0.pi_0 >= beta
    ## vb + v0.(pi_0 + 1) >= beta
    ## u0 + v0 = 1
    ## u, v, u0, v0 >= 0
    ## if min value comes out < 0, then (alpha.x >= beta) is a cut.
    ############################################################################

    pi = CyLPArray(pi)

    Atran = m.A.transpose()
    b = CyLPArray(m.b)
    numRows, numCols = m.A.shape

    if use_cylp:
        sp = CyLPModel()
        u = sp.addVariable('u', numRows, isInt=False)
        v = sp.addVariable('v', numRows, isInt=False)
        u0 = sp.addVariable('u0', 1, isInt=False)
        v0 = sp.addVariable('v0', 1, isInt=False)
        alpha = sp.addVariable('alpha', lp.nVariables, isInt=False)
        beta = sp.addVariable('beta', 1, isInt=False)

        #This should be as simple as this, but it doesn't work.
        #Maybe a bug in CyLP?
        #sp += alpha - Atran*u - pi*u0 == 0
        #sp += alpha - Atran*v + pi*v0 == 0
        for i in range(numCols):
            sp += alpha[i] - sum(Atran[i, j] * u[j]
                                 for j in range(numRows)) - pi[i] * u0 == 0
        for i in range(numCols):
            sp += alpha[i] - sum(Atran[i, j] * v[j]
                                 for j in range(numRows)) + pi[i] * v0 == 0
        if m.sense == '<=':
            sp += beta - b * u - pi0 * u0 >= 0
            sp += beta - b * v + (pi0 + 1) * v0 >= 0
        else:
            sp += beta - b * u - pi0 * u0 <= 0
            sp += beta - b * v + (pi0 + 1) * v0 <= 0
        sp += u0 + v0 == 1
        sp += u >= 0
        sp += v >= 0
        sp += u0 >= 0
        sp += v0 >= 0
        if m.sense == '<=':
            sp.objective = sum(-sol[i] * alpha[i]
                               for i in range(numCols)) + beta
        else:
            #This direction is not debugged
            sp.objective = sum(sol[i] * alpha[i]
                               for i in range(numCols)) - beta

        cglp = CyClpSimplex(sp)
        # If we want to solve it as an MILP
        # cglp = CyClpSimplex(sp).getCbcModel()
        #cglp.writeLp('lp.lp')
        cglp.logLevel = 0
        cglp.primal(startFinishOptions='x')
        # Solve as MILP
        # cglp.solve()
        beta = cglp.primalVariableSolution['beta'][0]
        alpha = cglp.primalVariableSolution['alpha']
        u = cglp.primalVariableSolution['u']
        v = cglp.primalVariableSolution['v']
        u0 = cglp.primalVariableSolution['u0'][0]
        v0 = cglp.primalVariableSolution['v0'][0]
        if debug_print:
            print(me, 'Objective Value: ', cglp.objectiveValue)

        if debug_print:
            print(me, 'u: ', u)
            print(me, 'v: ', v)
            print(me, 'u0: ', u0)
            print(me, 'v0: ', v0)
    else:
        CG = AbstractModel()
        CG.u = Var(list(range(numRows)),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.v = Var(list(range(numRows)),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.u0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.v0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.alpha = Var(list(range(numRows)), domain=Reals, bounds=(None, None))
        CG.beta = Var(domain=Reals, bounds=(None, None))

        ## Constraints
        def pi_rule_left(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.u[j] for j in range(numRows)) -
                    x * CG.u0 - CG.alpha[i] == 0.0)

        CG.pi_rule_left = Constraint(list(range(numCols)), rule=pi_rule_left)

        def pi_rule_right(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.v[j] for j in range(numRows)) +
                    x * CG.v0 - CG.alpha[i] == 0.0)

        CG.pi_rule_right = Constraint(list(range(numCols)), rule=pi_rule_right)

        if m.sense == '<=':

            def pi0_rule_left(CG):
                return (sum(b[j] * CG.u[j]
                            for j in range(numRows)) - pi0 * CG.u0 - CG.beta <=
                        0.0)

            CG.pi0_rule_left = Constraint(rule=pi0_rule_left)

            def pi0_rule_right(CG):
                return (sum(b[j] * CG.v[j] for j in range(numRows)) +
                        (pi0 + 1) * CG.v0 - CG.beta <= 0.0)

            CG.pi0_rule_right = Constraint(rule=pi0_rule_right)
        else:

            def pi0_rule_left(CG):
                return (sum(b[j] * CG.u[j]
                            for j in range(numRows)) - pi0 * CG.u0 - CG.beta >=
                        0.0)

            CG.pi0_rule_left = Constraint(rule=pi0_rule_left)

            def pi0_rule_right(CG):
                return (sum(b[j] * CG.v[j] for j in range(numRows)) +
                        (pi0 + 1) * CG.v0 - CG.beta >= 0.0)

            CG.pi0_rule_right = Constraint(rule=pi0_rule_right)

        def normalization_rule(CG):
            return (CG.u0 + CG.v0 == 1.0)

        CG.normalization_rule = Constraint(rule=normalization_rule)

        def objective_rule(CG):
            return (sum(sol[i] * CG.alpha[i]
                        for i in range(numCols)) - CG.beta)

        if m.sense == '<=':
            CG.objective = Objective(sense=maximize, rule=objective_rule)
        else:
            CG.objective = Objective(sense=minimize, rule=objective_rule)

        opt = SolverFactory("cbc")
        instance = CG.create_instance()
        #instance.pprint()
        #instance.write("foo.nl", format = "nl")
        #opt.options['bonmin.bb_log_level'] = 5
        #opt.options['bonmin.bb_log_interval'] = 1
        results = opt.solve(instance, tee=False)
        #results = opt.solve(instance)
        instance.solutions.load_from(results)

        beta = instance.beta.value
        alpha = np.array(
            [instance.alpha[i].value for i in range(lp.nVariables)])

    violation = beta - np.dot(alpha, sol)
    if debug_print:
        print(me, 'Beta: ', beta)
        print(me, 'alpha: ', alpha)
        print(me, 'Violation of cut: ', violation)

    if np.abs(violation) > 10**(-eps):
        return [(alpha, beta)]

    print('No violated cuts found solving CGLP', violation)
    return []
示例#16
0
def splitCuts(lp, integerIndices = None, sense = '>=', sol = None,
              max_coeff = 1):
    A = lp.coefMatrix
    b = CyLPArray(lp.constraintsUpper)
    if integerIndices is None:
        integerIndices = range(lp.nVariables)
    if sol is None:
        sol = lp.primalVariableSolution['x']
    s = A*sol - b
    best = lp.getCoinInfinity()
    best_theta = None

    for theta in [0.1, 0.2, 0.3, 0.4, 0.5]:
        sp = CyLPModel()
        u = sp.addVariable('u', lp.nConstraints, isInt = False)
        v = sp.addVariable('v', lp.nConstraints, isInt = False)
        pi = sp.addVariable('pi', lp.nVariables, isInt = True)
        pi0 = sp.addVariable('pi0', 1, isInt = True)
    
        sp += pi + A.transpose()*u - A.transpose()*v == 0
        sp += pi0 + b*u - b*v == theta - 1
        if sense == '<=':
            sp += u >= 0
            sp += v >= 0
        else:
            #TODO this direction is not debugged
            # Is this all we need?
            sp += u <= 0
            sp += v <= 0
            
        sp.objective = (theta-1)*s*u - theta*s*v
        for i in xrange(lp.nVariables):
            if i in integerIndices:
                sp += -max_coeff <= pi[i] <= max_coeff
            else:
                sp[i] += pi[i] == 0

        cbcModel = CyClpSimplex(sp).getCbcModel()
        cbcModel.logLevel = 0
        #cbcModel.maximumSeconds = 5
        cbcModel.solve()
        if debug_print:
            print theta, cbcModel.objectiveValue
            print cbcModel.primalVariableSolution['pi'], 
            print cbcModel.primalVariableSolution['pi0']
        if cbcModel.objectiveValue < best:
            best = cbcModel.objectiveValue
            multu = cbcModel.primalVariableSolution['u']
            disjunction = cbcModel.primalVariableSolution['pi']
            rhs = cbcModel.primalVariableSolution['pi0']
            best_theta = theta
            
    if best_theta is not None:
        alpha = A.transpose()*multu + best_theta*disjunction
        if sense == '<=':
            beta = np.dot(lp.constraintsUpper, multu) + best_theta*rhs
        else:
            beta = np.dot(lp.constraintsLower, multu) + best_theta*rhs
        if (abs(alpha) > 1e-6).any():
            return [(alpha, beta)] 
    return []
示例#17
0
def disjunctionToCut(lp,
                     pi,
                     pi0,
                     integerIndices=None,
                     sense='>=',
                     sol=None,
                     debug_print=False,
                     use_cylp=True):

    me = "cglp_cuts: "

    if sol is None:
        sol = lp.primalVariableSolution['x']
    infinity = lp.getCoinInfinity()

    if debug_print:
        print(me, "constraints sense = ", sense)
        print(me, "con lower bounds = ", lp.constraintsLower)
        print(me, "con upper bounds = ", lp.constraintsUpper)
        print(me, "con matrix = ", lp.coefMatrix.toarray())
        print(me, "vars lower bounds = ", lp.variablesLower)
        print(me, "vars upper bounds = ", lp.variablesUpper)
        print(me, "Assuming objective is to minimize")
        print(me, "objective = ", lp.objective)
        print(me, "infinity = ", infinity)
        print(me, "current point = ", sol)
        print(me, "pi = ", pi)
        print(me, "pi0 = ", pi0)

    A = lp.coefMatrix.toarray()
    #c = lp.objective
    ## Convert to >= if the problem is in <= form.
    if sense == '<=':
        b = deepcopy(lp.constraintsUpper)
        b = -1.0 * b
        A = -1.0 * A
    else:
        b = deepcopy(lp.constraintsLower)

    #Add bounds on variables as explicit constraints
    for i in range(lp.nCols):
        e = np.zeros((1, lp.nCols))
        if lp.variablesUpper[i] < infinity:
            b.resize(b.size + 1, refcheck=False)
            e[0, i] = -1.0
            b[-1] = -1.0 * lp.variablesUpper[i]
            A = np.vstack((A, e))
        if lp.variablesLower[i] > -infinity:
            b.resize(b.size + 1, refcheck=False)
            e[0, i] = 1.0
            b[-1] = lp.variablesLower[i]
            A = np.vstack((A, e))
    A = csc_matrixPlus(A)

    ############################################################################
    ## There are two given LPs:
    ## s.t. Ax >= b           s.t. Ax >= b
    ##   -pi.x >= -pi_0          pi.x >= pi_0+1
    ## A, b, c, pi, pi_0 are given
    ##
    ## CGLP: alpha.x >= beta should be valid for both LPs above
    ##
    ## min alpha.x* - beta
    ## uA - u0.pi = alpha
    ## vA + v0.pi = alpha
    ## ub - u0.pi_0 >= beta
    ## vb + v0.(pi_0 + 1) >= beta
    ## u0 + v0 = 1
    ## u, v, u0, v0 >= 0
    ## if min value comes out < 0, then (alpha.x >= beta) is a cut.
    ############################################################################

    b = CyLPArray(b)
    pi = CyLPArray(pi)

    Atran = A.transpose()

    if use_cylp:
        sp = CyLPModel()
        u = sp.addVariable('u', A.shape[0], isInt=False)
        v = sp.addVariable('v', A.shape[0], isInt=False)
        u0 = sp.addVariable('u0', 1, isInt=False)
        v0 = sp.addVariable('v0', 1, isInt=False)
        alpha = sp.addVariable('alpha', lp.nVariables, isInt=False)
        beta = sp.addVariable('beta', 1, isInt=False)

        for i in range(A.shape[1]):
            sp += alpha[i] - sum(Atran[i, j] * u[j]
                                 for j in range(A.shape[0])) + pi[i] * u0 == 0
        for i in range(A.shape[1]):
            sp += alpha[i] - sum(Atran[i, j] * v[j]
                                 for j in range(A.shape[0])) - pi[i] * v0 == 0
        sp += beta - b * u + pi0 * u0 <= 0
        sp += beta - b * v - (pi0 + 1) * v0 <= 0
        sp += u0 + v0 == 1
        if sense == '<=':
            sp += u >= 0
            sp += v >= 0
            sp += u0 >= 0
            sp += v0 >= 0
        else:
            #TODO this direction is not debugged
            # Is this all we need?
            sp += u <= 0
            sp += v <= 0
            sp += u0 <= 0
            sp += v0 <= 0
        sp.objective = sum(sol[i] * alpha[i] for i in range(A.shape[1])) - beta
        cbcModel = CyClpSimplex(sp).getCbcModel()
        cbcModel.logLevel = 0
        #cbcModel.maximumSeconds = 5
        cbcModel.solve()
        beta = cbcModel.primalVariableSolution['beta'][0]
        alpha = cbcModel.primalVariableSolution['alpha']
        u = cbcModel.primalVariableSolution['u']
        v = cbcModel.primalVariableSolution['v']
        u0 = cbcModel.primalVariableSolution['u0'][0]
        v0 = cbcModel.primalVariableSolution['v0'][0]
        if debug_print:
            print('Objective Value: ', cbcModel.objectiveValue)
            print('alpha: ', alpha, 'alpha*sol: ', np.dot(alpha, sol))
            print('beta: ', beta)
            print('Violation of cut: ', np.dot(alpha, sol) - beta)
    else:
        CG = AbstractModel()
        CG.u = Var(list(range(A.shape[0])),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.v = Var(list(range(A.shape[0])),
                   domain=NonNegativeReals,
                   bounds=(0.0, None))
        CG.u0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.v0 = Var(domain=NonNegativeReals, bounds=(0.0, None))
        CG.alpha = Var(list(range(A.shape[0])),
                       domain=Reals,
                       bounds=(None, None))
        CG.beta = Var(domain=Reals, bounds=(None, None))

        ## Constraints
        def pi_rule_left(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.u[j] for j in range(A.shape[0])) -
                    x * CG.u0 - CG.alpha[i] == 0.0)

        CG.pi_rule_left = Constraint(list(range(A.shape[1])),
                                     rule=pi_rule_left)

        def pi_rule_right(CG, i):
            x = float(pi[i])
            return (sum(Atran[i, j] * CG.v[j] for j in range(A.shape[0])) +
                    x * CG.v0 - CG.alpha[i] == 0.0)

        CG.pi_rule_right = Constraint(list(range(A.shape[1])),
                                      rule=pi_rule_right)

        def pi0_rule_left(CG):
            return (sum(b[j] * CG.u[j]
                        for j in range(A.shape[0])) - pi0 * CG.u0 - CG.beta >=
                    0.0)

        CG.pi0_rule_left = Constraint(rule=pi0_rule_left)

        def pi0_rule_right(CG):
            return (sum(b[j] * CG.v[j] for j in range(A.shape[0])) +
                    (pi0 + 1) * CG.v0 - CG.beta >= 0.0)

        CG.pi0_rule_right = Constraint(rule=pi0_rule_right)

        def normalization_rule(CG):
            return (CG.u0 + CG.v0 == 1.0)

        CG.normalization_rule = Constraint(rule=normalization_rule)

        def objective_rule(CG):
            return (sum(sol[i] * CG.alpha[i]
                        for i in range(A.shape[1])) - CG.beta)

        CG.objective = Objective(sense=minimize, rule=objective_rule)

        opt = SolverFactory("cbc")
        instance = CG.create_instance()
        #instance.pprint()
        #instance.write("foo.nl", format = "nl")
        #opt.options['bonmin.bb_log_level'] = 5
        #opt.options['bonmin.bb_log_interval'] = 1
        results = opt.solve(instance, tee=False)
        #results = opt.solve(instance)
        instance.solutions.load_from(results)

        beta = instance.beta.value
        alpha = np.array(
            [instance.alpha[i].value for i in range(lp.nVariables)])
    violation = beta - np.dot(alpha, sol)
    if debug_print:
        print(me, 'Beta: ', beta)
        print(me, 'alpha: ', alpha)
        print(me, 'Violation of cut: ', violation)

    if violation > 0.001:
        if (sense == ">="):
            return [(alpha, beta)]
        else:
            return [(-alpha, -beta)]
    return []