Exemplo n.º 1
0
    def setUp(self):
        'Test remove constraint'

        model = CyLPModel()

        x = model.addVariable('x', 3)
        y = model.addVariable('y', 2)

        A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])),  shape=(2, 3))
        B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])),  shape=(2, 3))
        D = np.matrix([[1., 2.],[0, 1]])
        a = CyLPArray([3, 2.5])
        b = CyLPArray([4.2, 3])
        x_u= CyLPArray([2., 3.5])

        model.addConstraint(A * x <= a, 'res1')
        model.addConstraint(2 <= B * x + D * y <= b, 'res2')
        model.addConstraint(y >= 0)
        model.addConstraint(1.1 <= x[1:3] <= x_u)
        model.addConstraint(x[0] >= 0.1)

        c = CyLPArray([1., -2., 3.])
        model.objective = c * x + 2 * y[0] + 2 * y[1]

        s = CyClpSimplex(model)
        self.s = s
        self.x = x
        self.y = y
    def test_Sparse(self):
        model = CyLPModel()

        x = model.addVariable('x', 3)
        y = model.addVariable('y', 2)

        A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])),
                           shape=(2, 3))
        B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])), shape=(2, 3))
        D = np.matrix([[1., 2.], [0, 1]])
        a = CyLPArray([5, 2.5])
        b = CyLPArray([4.2, 3])
        x_u = CyLPArray([2., 3.5])

        model.addConstraint(A * x <= a)
        model.addConstraint(2 <= B * x + D * y <= b)
        model.addConstraint(y >= 0)
        model.addConstraint(1.1 <= x[1:3] <= x_u)

        c = CyLPArray([1., -2., 3.])
        model.objective = c * x + 2 * y[0] + 2 * y[1]

        s = CyClpSimplex(model)

        s.primal()
        sol = np.concatenate(
            (s.primalVariableSolution['x'], s.primalVariableSolution['y']))
        self.assertTrue(
            (abs(sol - np.array([0.2, 2, 1.1, 0, 0.9])) <= 10**-6).all())
Exemplo n.º 3
0
    def test_Sparse(self):
        model = CyLPModel()

        x = model.addVariable('x', 3)
        y = model.addVariable('y', 2)

        A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])),  shape=(2, 3))
        B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])),  shape=(2, 3))
        D = np.matrix([[1., 2.],[0, 1]])
        a = CyLPArray([5, 2.5])
        b = CyLPArray([4.2, 3])
        x_u= CyLPArray([2., 3.5])

        model.addConstraint(A*x <= a)
        model.addConstraint(2 <= B * x + D * y <= b)
        model.addConstraint(y >= 0)
        model.addConstraint(1.1 <= x[1:3] <= x_u)

        c = CyLPArray([1., -2., 3.])
        model.objective = c * x + 2 * y[0] + 2 * y[1]


        s = CyClpSimplex(model)

        s.primal()
        sol = np.concatenate((s.primalVariableSolution['x'],
                              s.primalVariableSolution['y']))
        self.assertTrue((abs(sol -
                        np.array([0.2, 2, 1.1, 0, 0.9]) ) <= 10**-6).all())
Exemplo n.º 4
0
    def setUp(self):
        'Test remove constraint'

        model = CyLPModel()

        x = model.addVariable('x', 3)
        y = model.addVariable('y', 2)

        A = csc_matrixPlus(([1, 2, 1, 1], ([0, 0, 1, 1], [0, 1, 0, 2])),
                           shape=(2, 3))
        B = csc_matrixPlus(([1, 1], ([0, 1], [0, 2])), shape=(2, 3))
        D = np.matrix([[1., 2.], [0, 1]])
        a = CyLPArray([3, 2.5])
        b = CyLPArray([4.2, 3])
        x_u = CyLPArray([2., 3.5])

        model.addConstraint(A * x <= a, 'res1')
        model.addConstraint(2 <= B * x + D * y <= b, 'res2')
        model.addConstraint(y >= 0)
        model.addConstraint(1.1 <= x[1:3] <= x_u)
        model.addConstraint(x[0] >= 0.1)

        c = CyLPArray([1., -2., 3.])
        model.objective = c * x + 2 * y[0] + 2 * y[1]

        s = CyClpSimplex(model)
        self.s = s
        self.x = x
        self.y = y
Exemplo n.º 5
0
 def test_scale_scale(self):
     m = csc_matrixPlus(([1, 2, 6, 4, 5, 7, 3, 2],
                         ([0, 0, 1, 1, 1, 2, 2, 2], [0, 1, 0, 2, 3, 0, 2, 3])),
                         shape=(3, 4), dtype=np.float)
     unscaledM = m.copy()
     row_scale = m.row_scale()
     col_scale = m.col_scale()
     m.col_scale(1/col_scale)
     m.row_scale(1/row_scale)
     assert(((m - unscaledM).todense() < 1.0e-7).all())
Exemplo n.º 6
0
 def test_scale_scale(self):
     m = csc_matrixPlus(
         ([1, 2, 6, 4, 5, 7, 3, 2], ([0, 0, 1, 1, 1, 2, 2, 2], [0, 1, 0, 2, 3, 0, 2, 3])),
         shape=(3, 4),
         dtype=np.float,
     )
     unscaledM = m.copy()
     row_scale = m.row_scale()
     col_scale = m.col_scale()
     m.col_scale(1 / col_scale)
     m.row_scale(1 / row_scale)
     assert ((m - unscaledM).todense() < 1.0e-7).all()
Exemplo n.º 7
0
    def makeMatrices(self):
        '''
        Makes coef matrix and rhs vector from CyLPConstraints
        in self.constraints
        '''
        #if len(self.constraints) == 0:
        #    return
        self.makeIndexFactory()
        #self.getVarBounds()


        # Create the aggregated coef matrix
        masterCoefMat = None

        masterCoefMat = None
        if self.nCons > 0:
            for varName in self.varNames:# self.pvdims.keys():#self.allVarNames:
                vmat = self.generateVarMatrix(varName)

                if vmat is None:
                    vmat = csc_matrixPlus((self.nCons, self.pvdims[varName]))
                masterCoefMat = sparseConcat(masterCoefMat, vmat, 'h')

        # Create bound vectors
        c_lower = np.array([])
        c_upper = np.array([])
        for c in self.constraints:
            if not c.isRange:
                c_lower = np.concatenate((c_lower, c.lower), axis=0)
                c_upper = np.concatenate((c_upper, c.upper), axis=0)
        # Create variables bound vectors
        v_lower = np.array([])
        v_upper = np.array([])
        if self.nVars:
            v_lower = -getCoinInfinity() * np.ones(self.nVars)
            v_upper = getCoinInfinity() * np.ones(self.nVars)
            for v in self.variables:
                varinds = self.inds.varIndex[v.name]
                v_lower[varinds] = v.lower
                v_upper[varinds] = v.upper

                #v_lower = np.concatenate((v_lower, v.lower), axis=0)
                #v_upper = np.concatenate((v_upper, v.upper), axis=0)
        #if masterCoefMat is not None:
        return masterCoefMat, c_lower, c_upper, v_lower, v_upper
Exemplo n.º 8
0
    def makeMatrices(self):
        '''
        Makes coef matrix and rhs vector from CyLPConstraints
        in self.constraints
        '''
        #if len(self.constraints) == 0:
        #    return
        self.makeIndexFactory()
        #self.getVarBounds()


        # Create the aggregated coef matrix
        masterCoefMat = None

        masterCoefMat = None
        if self.nCons > 0:
            for varName in self.varNames:# self.pvdims.keys():#self.allVarNames:
                vmat = self.generateVarMatrix(varName)

                if vmat is None:
                    vmat = csc_matrixPlus((self.nCons, self.pvdims[varName]))
                masterCoefMat = sparseConcat(masterCoefMat, vmat, 'h')

        # Create bound vectors
        c_lower = np.array([])
        c_upper = np.array([])
        for c in self.constraints:
            if not c.isRange:
                c_lower = np.concatenate((c_lower, c.lower), axis=0)
                c_upper = np.concatenate((c_upper, c.upper), axis=0)
        # Create variables bound vectors
        v_lower = np.array([])
        v_upper = np.array([])
        if self.nVars:
            v_lower = -getCoinInfinity() * np.ones(self.nVars)
            v_upper = getCoinInfinity() * np.ones(self.nVars)
            for v in self.variables:
                varinds = self.inds.varIndex[v.name]
                v_lower[varinds] = v.lower
                v_upper[varinds] = v.upper

                #v_lower = np.concatenate((v_lower, v.lower), axis=0)
                #v_upper = np.concatenate((v_upper, v.upper), axis=0)
        #if masterCoefMat is not None:
        return masterCoefMat, c_lower, c_upper, v_lower, v_upper
Exemplo n.º 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 []
Exemplo n.º 10
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 []