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']]
    def test(self):
        model = CyLPModel()

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

        A = np.matrix([[1, 2, 3], [1, 1, 1]])
        b = CyLPArray([5, 3])

        model.addConstraint(A * x == b)
        model.addConstraint(x >= 0)

        model.objective = 1 * x[0] + 1 * x[1] + 1.1 * x[2]

        # Solve it a first time
        s = CyClpSimplex(model)
        s.primal()
        sol = s.primalVariableSolution['x']
        self.assertTrue((abs(sol - np.array([1, 2, 0])) <= 10**-6).all())
        # Add a cut
        s.addConstraint(x[0] >= 1.1)
        s.primal()
        sol = s.primalVariableSolution['x']
        self.assertTrue((abs(sol - np.array([1.1, 1.8, 0.1])) <= 10**-6).all())

        # Change the objective function
        c = csr_matrixPlus([[1, 10, 1.1]]).T
        s.objective = c.T * x
        s.primal()
        sol = s.primalVariableSolution['x']
        self.assertTrue((abs(sol - np.array([2, 0, 1])) <= 10**-6).all())
Example #3
0
    def test_isInt(self):
        self.model = CyLPModel()
        model = self.model

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

        A = np.matrix([[1., 2., 0], [1., 0, 1.]])
        B = np.matrix([[1., 0, 0], [0, 0, 1.]])
        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.sum()

        self.s = CyClpSimplex(model)
        s = self.s

        cbcModel = s.getCbcModel()

        cbcModel.branchAndBound()

        sol_x = cbcModel.primalVariableSolution['x']
        self.assertTrue((abs(sol_x - np.array([0, 2, 2])) <= 10**-6).all())
        sol_y = cbcModel.primalVariableSolution['y']
        self.assertTrue((abs(sol_y - np.array([0, 1])) <= 10**-6).all())
Example #4
0
    def test_write(self):
        self.model = CyLPModel()
        model = self.model

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

        A = np.matrix([[1., 2., 0], [1., 0, 1.]])
        B = np.matrix([[1., 0, 0], [0, 0, 1.]])
        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.sum()

        self.s = CyClpSimplex(model)
        s = self.s

        s.writeMps("cylptest.mps")
        os.remove("cylptest.mps")
        s.writeMps("cylptest.lp")
        os.remove("cylptest.lp")
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 test(self):
        model = CyLPModel()

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

        A = np.matrix([[1,2,3], [1,1,1]])
        b = CyLPArray([5, 3])

        model.addConstraint(A * x == b)
        model.addConstraint(x >= 0)

        model.objective = 1*x[0]  + 1*x[1] + 1.1 * x[2]

        # Solve it a first time
        s = CyClpSimplex(model)
        s.primal()
        sol = s.primalVariableSolution['x']
        self.assertTrue((abs(sol - np.array([1,2,0]) ) <= 10**-6).all())
        # Add a cut
        s.addConstraint(x[0] >= 1.1)
        s.primal()
        sol = s.primalVariableSolution['x']
        self.assertTrue((abs(sol - np.array([1.1, 1.8, 0.1]) ) <= 10**-6).all())

        # Change the objective function
        c = csr_matrixPlus([[1, 10, 1.1]]).T
        s.objective = c.T * x
        s.primal()
        sol = s.primalVariableSolution['x']
        self.assertTrue((abs(sol - np.array([2, 0, 1]) ) <= 10**-6).all())
    def test_onlyBounds(self):
        model = CyLPModel()

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

        model += y >= 1
        model += 2 <= x <= 4

        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([2, 4, 2, 1, 1])) <= 10**-6).all())
    def test_onlyBounds(self):
        model = CyLPModel()

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

        model += y >= 1
        model += 2 <= x <= 4

        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([2, 4, 2, 1, 1]) ) <= 10**-6).all())
Example #9
0
    def setUp(self):
        self.model = CyLPModel()
        model = self.model

        self.x = model.addVariable('x', 5)

        self.b = np.array([3.1, 4.2])

        self.A = np.matrix([[1, 2, 3, 3, 4], [3, 2, 1, 2, 5]])
        self.B = np.matrix([[0, 0, 0, -1.5, -1.5], [-3, 0, 0, -2, 0]])
        self.D = np.matrix([[1, 3, 1, 4], [2, 1, 3, 5]])
Example #10
0
    def test_SetInt_CopyIn(self):
        self.model = CyLPModel()
        model = self.model

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

        A = np.matrix([[1., 2., 0],[1., 0, 1.]])
        B = np.matrix([[1., 0, 0], [0, 0, 1.]])
        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.sum()


        self.s = CyClpSimplex(model)
        s = self.s
        s.setInteger(x[1:3])

        cbcModel = s.getCbcModel()
        cbcModel.branchAndBound()

        sol_x = cbcModel.primalVariableSolution['x']
        self.assertTrue((abs(sol_x -
                        np.array([0.5, 2, 2]) ) <= 10**-6).all())
        sol_y = cbcModel.primalVariableSolution['y']
        self.assertTrue((abs(sol_y -
                        np.array([0, 0.75]) ) <= 10**-6).all())


        s.copyInIntegerInformation(np.array(
                            [True, False, False, False, True], np.uint8))
        cbcModel = s.getCbcModel()
        cbcModel.branchAndBound()

        sol_x = cbcModel.primalVariableSolution['x']
        self.assertTrue((abs(sol_x -
                        np.array([0, 2, 1.1]) ) <= 10**-6).all())
        sol_y = cbcModel.primalVariableSolution['y']
        self.assertTrue((abs(sol_y -
                        np.array([0, 1]) ) <= 10**-6).all())
    def test_removeConstraint(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)
        s.primal()
        sol = np.concatenate((s.primalVariableSolution['x'],
                              s.primalVariableSolution['y']))
        self.assertTrue((abs(sol -
                        np.array([0.1, 1.45, 1.1, 0, 0.95]) ) <= 10**-6).all())

        s.removeConstraint('res2')
        s.primal()
        sol = np.concatenate((s.primalVariableSolution['x'],
                              s.primalVariableSolution['y']))
        self.assertTrue((abs(sol -
                        np.array([0.1, 1.45, 1.1, 0, 0]) ) <= 10**-6).all())

        s.removeConstraint('res1')
        s.primal()
        sol = np.concatenate((s.primalVariableSolution['x'],
                              s.primalVariableSolution['y']))
        self.assertTrue((abs(sol -
                        np.array([0.1, 2, 1.1, 0, 0]) ) <= 10**-6).all())
Example #12
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 Single_Year_Stage_II(puf, Stage_I_factors, Stage_II_targets, year, tol):


    length = len(puf.s006)


    print("Preparing coefficient matrix...")

    s006 = np.where(puf.e02400>0,
                    puf.s006*Stage_I_factors[year]["APOPSNR"]/100,
                    puf.s006*Stage_I_factors[year]["ARETS"]/100)



    single_return = np.where((puf.mars==1) & (puf.filer==1), s006, 0)
    joint_return = np.where(((puf.mars==2)|(puf.mars==3)) & (puf.filer==1), s006, 0)
    hh_return = np.where((puf.mars==4) & (puf.filer==1),s006,0)
    return_w_SS = np.where((puf.e02400>0) & (puf.filer==1),s006,0)

    dependent_exempt_num = (puf.xocah+puf.xocawh+puf.xoodep+puf.xopar)*s006
    interest = puf.e00300*s006
    dividend = puf.e00600*s006
    biz_income = np.where(puf.e00900>0, puf.e00900, 0)*s006
    biz_loss = np.where(puf.e00900<0, -puf.e00900, 0)*s006
    cap_gain = np.where((puf.p23250+puf.p22250)>0, (puf.p23250+puf.p22250), 0)*s006
    annuity_pension = puf.e01700*s006
    sch_e_income = np.where(puf.e02000>0, puf.e02000, 0)*s006
    sch_e_loss = np.where(puf.e02000<0, -puf.e02000, 0)*s006
    ss_income = puf.e02400*s006
    unemployment_comp = puf.e02300*s006


    # Wage distribution

    wage_1 = np.where(puf.e00100<=0, puf.e00200,0)*s006
    wage_2 = np.where((puf.e00100>0)&(puf.e00100<=10000), puf.e00200,0)*s006
    wage_3 = np.where((puf.e00100>10000)&(puf.e00100<=20000), puf.e00200,0)*s006
    wage_4 = np.where((puf.e00100>20000)&(puf.e00100<=30000), puf.e00200,0)*s006
    wage_5 = np.where((puf.e00100>30000)&(puf.e00100<=40000), puf.e00200,0)*s006
    wage_6 = np.where((puf.e00100>40000)&(puf.e00100<=50000), puf.e00200,0)*s006
    wage_7 = np.where((puf.e00100>50000)&(puf.e00100<=75000), puf.e00200,0)*s006
    wage_8 = np.where((puf.e00100>75000)&(puf.e00100<=100000), puf.e00200,0)*s006
    wage_9 = np.where((puf.e00100>100000)&(puf.e00100<=200000), puf.e00200,0)*s006
    wage_10 = np.where((puf.e00100>200000)&(puf.e00100<=500000), puf.e00200,0)*s006
    wage_11 = np.where((puf.e00100>500000)&(puf.e00100<=1000000), puf.e00200,0)*s006
    wage_12 = np.where((puf.e00100>1000000), puf.e00200,0)*s006


    # Set up the matrix
    One_half_LHS = np.vstack((single_return, joint_return, hh_return, return_w_SS,
                              dependent_exempt_num, interest, dividend,
                              biz_income,biz_loss, cap_gain, annuity_pension,
                              sch_e_income, sch_e_loss, ss_income, unemployment_comp,
                              wage_1, wage_2, wage_3, wage_4, wage_5, wage_6,
                              wage_7, wage_8, wage_9, wage_10, wage_11, wage_12))


    # Coefficients for r and s
    A1 = np.matrix(One_half_LHS)
    A2 = np.matrix(-One_half_LHS)


    print("Preparing targets for ", year)

    APOPN = Stage_I_factors[year]["APOPN"]

    b = []

    b.append(Stage_II_targets[year]['Single Returns']-single_return.sum())
    b.append(Stage_II_targets[year]['Joint Returns']-joint_return.sum())
    b.append(Stage_II_targets[year]['Head of Household Returns']-hh_return.sum())
    b.append(Stage_II_targets[year]['Number of Returns w/ Gross Security Income']-return_w_SS.sum())

    b.append(Stage_II_targets[year]['Number of Dependent Exemptions'] -  dependent_exempt_num.sum())

    AINTS = Stage_I_factors[year]["AINTS"]
    INTEREST = Stage_II_targets[year]['Taxable Interest Income']*APOPN/AINTS*1000-interest.sum()

    ADIVS = Stage_I_factors[year]["ADIVS"]
    DIVIDEND = Stage_II_targets[year]['Ordinary Dividends']*APOPN/ADIVS*1000 - dividend.sum()

    ASCHCI = Stage_I_factors[year]["ASCHCI"]
    BIZ_INCOME = Stage_II_targets[year]['Business Income (Schedule C)']*APOPN/ASCHCI*1000 - biz_income.sum()


    ASCHCL = Stage_I_factors[year]["ASCHCL"]
    BIZ_LOSS = Stage_II_targets[year]['Business Loss (Schedule C)']*APOPN/ASCHCL*1000 - biz_loss.sum()

    ACGNS = Stage_I_factors[year]["ACGNS"]
    CAP_GAIN = Stage_II_targets[year]['Net Capital Gains in AGI']*APOPN/ACGNS*1000 - cap_gain.sum()

    ATXPY = Stage_I_factors[year]["ATXPY"]
    ANNUITY_PENSION = Stage_II_targets[year]['Taxable Pensions and Annuities']*APOPN/ATXPY*1000 - annuity_pension.sum()

    ASCHEI = Stage_I_factors[year]["ASCHEI"]
    SCH_E_INCOME = Stage_II_targets[year]["Supplemental Income (Schedule E)"]*APOPN/ASCHEI*1000 - sch_e_income.sum()

    ASCHEL = Stage_I_factors[year]["ASCHEL"]
    SCH_E_LOSS = Stage_II_targets[year]["Supplemental Loss (Schedule E)"]*APOPN/ASCHEL*1000 - sch_e_loss.sum()

    ASOCSEC = Stage_I_factors[year]["ASOCSEC"]
    APOPSNR = Stage_I_factors[year]["APOPSNR"]
    SS_INCOME = Stage_II_targets[year]["Gross Social Security Income"]*APOPSNR/ASOCSEC*1000 - ss_income.sum()

    AUCOMP = Stage_I_factors[year]["AUCOMP"]
    UNEMPLOYMENT_COMP = Stage_II_targets[year]["Unemployment Compensation"]*APOPN/AUCOMP*1000 - unemployment_comp.sum()

    AWAGE = Stage_I_factors[year]["AWAGE"]
    WAGE_1 = Stage_II_targets[year]["Wages and Salaries: Zero or Less"]*APOPN/AWAGE*1000 - wage_1.sum()
    WAGE_2 = Stage_II_targets[year]["Wages and Salaries: $1 Less Than $10,000"]*APOPN/AWAGE*1000 - wage_2.sum()
    WAGE_3 = Stage_II_targets[year]["Wages and Salaries: $10,000 Less Than $20,000"]*APOPN/AWAGE*1000 - wage_3.sum()
    WAGE_4 = Stage_II_targets[year]["Wages and Salaries: $20,000 Less Than $30,000"]*APOPN/AWAGE*1000 - wage_4.sum()
    WAGE_5 = Stage_II_targets[year]["Wages and Salaries: $30,000 Less Than $40,000"]*APOPN/AWAGE*1000 - wage_5.sum()
    WAGE_6 = Stage_II_targets[year]["Wages and Salaries: $40,000 Less Than $50,000"]*APOPN/AWAGE*1000 - wage_6.sum()
    WAGE_7 = Stage_II_targets[year]["Wages and Salaries: $50,000 Less Than $75,000"]*APOPN/AWAGE*1000 - wage_7.sum()
    WAGE_8 = Stage_II_targets[year]["Wages and Salaries: $75,000 Less Than $100,000"]*APOPN/AWAGE*1000 - wage_8.sum()
    WAGE_9 = Stage_II_targets[year]["Wages and Salaries: $100,000 Less Than $200,000"]*APOPN/AWAGE*1000 - wage_9.sum()
    WAGE_10 = Stage_II_targets[year]["Wages and Salaries: $200,000 Less Than $500,000"]*APOPN/AWAGE*1000 - wage_10.sum()
    WAGE_11 = Stage_II_targets[year]["Wages and Salaries: $500,000 Less Than $1 Million"]*APOPN/AWAGE*1000 - wage_11.sum()
    WAGE_12 = Stage_II_targets[year]["Wages and Salaries: $1 Million and Over"]*APOPN/AWAGE*1000 - wage_12.sum()



    temp = [INTEREST,DIVIDEND, BIZ_INCOME, BIZ_LOSS, CAP_GAIN, ANNUITY_PENSION, SCH_E_INCOME, SCH_E_LOSS, SS_INCOME, UNEMPLOYMENT_COMP,
            WAGE_1,WAGE_2, WAGE_3,WAGE_4, WAGE_5, WAGE_6, WAGE_7,WAGE_8,WAGE_9, WAGE_10, WAGE_11, WAGE_12]
    for m in temp:
        b.append(m)

    targets = CyLPArray(b)
    print("Targets for year ", year, " is ", targets)

    LP = CyLPModel()

    r = LP.addVariable('r', length)
    s = LP.addVariable('s', length)

    print("Adding constraints")
    LP.addConstraint(r >=0, "positive r")
    LP.addConstraint(s >=0, "positive s")
    LP.addConstraint(r + s <= tol, "abs upperbound")

    c = CyLPArray((np.ones(length)))
    LP.objective = c * r + c * s




    LP.addConstraint(A1 * r + A2 * s == targets, "Aggregates")

    print("Setting up the LP model")
    model = CyClpSimplex(LP)


    print("Solving LP......")
    model.initialSolve()

    print("DONE!!")
    z = np.empty([length])
    z = (1+model.primalVariableSolution['r'] - model.primalVariableSolution['s'])*s006 * 100
    return z
Example #14
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 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
    def test_multiVar(self):
        model = CyLPModel()

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

        A = np.matrix([[1., 2., 0],[1., 0, 1.]])
        B = np.matrix([[1., 0, 0], [0, 0, 1.]])
        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())


        s += x[2] + y[1] >= 2.1
        s.primal()
        sol = np.concatenate((s.primalVariableSolution['x'],
                              s.primalVariableSolution['y']))
        self.assertTrue((abs(sol -
                        np.array([0, 2, 1.1, 0, 1]) ) <= 10**-6).all())
Example #17
0
    def solve_cylp(self, verbose: bool = True, **kwargs):
        """ Inspired by the cvxpy cbc layer, ty :) """
        from cylp.cy import CyClpSimplex
        from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray

        cons = self.combine_cons()
        n = int(self.next_var_idx - 1)  # Number of variables.

        # Maximize c@x s.t. A@x <= b  (variable bounds done by constraints)
        c = self.objective.rawdense().squeeze()[
            1:n + 1]  # Objective coefficients, no constants.
        A = cons.raw()[:, 1:n + 1]  # Constraint coefficients.
        b = cons[:, 0].rawdense().squeeze() * -1.0  # Constraint constants.

        model = CyLPModel()
        x = model.addVariable("x", n)  # Variables
        model.objective = c

        # I hate this so much. Casting A to a matrix causes A.__mul__ to be
        # be called, which raises NotImplemented, so then x.__rmul__ is called
        # which gets the job done. Using np.matmul or np.dot doesn't
        # trigger x.__rmul__
        # model.addConstraint(np.matrix(A) * x <= CyLPArray(b))  # Works
        model.addConstraint(x.__rmul__(A) <= CyLPArray(b))

        model = CyClpSimplex(model)  # Convert model

        model.logLevel = 0 if not verbose else model.logLevel

        is_integer_model = not np.isclose(self.int_vars.sum(), 0)
        if is_integer_model:
            model.setInteger(x[np.argwhere(self.int_vars)])
            cbcModel = model.getCbcModel()
            cbcModel.solve()
            status = cbcModel.status
            solmodel = cbcModel
        else:
            status = model.initialSolve()
            solmodel = model

        sol_x = np.hstack(  # Pad back to original shape
            (
                [1.0],  # Special constant 1.0 variable.
                solmodel.primalVariableSolution["x"],  # Actual solution
                np.zeros(self.max_vars - n - 1),  # Unused vars
            ))

        solution = {
            "status": status,
            "primal": sol_x,
            "value": solmodel.objectiveValue
        }
        return solution, solution["primal"]
    def test_removeConstraint(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)
        s.primal()
        sol = np.concatenate(
            (s.primalVariableSolution['x'], s.primalVariableSolution['y']))
        self.assertTrue(
            (abs(sol - np.array([0.1, 1.45, 1.1, 0, 0.95])) <= 10**-6).all())

        s.removeConstraint('res2')
        s.primal()
        sol = np.concatenate(
            (s.primalVariableSolution['x'], s.primalVariableSolution['y']))
        self.assertTrue(
            (abs(sol - np.array([0.1, 1.45, 1.1, 0, 0])) <= 10**-6).all())

        s.removeConstraint('res1')
        s.primal()
        sol = np.concatenate(
            (s.primalVariableSolution['x'], s.primalVariableSolution['y']))
        self.assertTrue(
            (abs(sol - np.array([0.1, 2, 1.1, 0, 0])) <= 10**-6).all())
Example #19
0
def BranchAndBound(T, CONSTRAINTS, VARIABLES, OBJ, MAT, RHS,
                   branch_strategy=MOST_FRACTIONAL,
                   search_strategy=DEPTH_FIRST,
                   complete_enumeration=False,
                   display_interval=None,
                   binary_vars=True,
                   solver='dynamic',
                   rel_param=(4, 3, 1 / 6, 5),
                   more_return=False
                   ):
    """
        solver: 
            dynamic       - initialSolve
            primalSimplex - initialPrimalSolve 
            dualSimplex   - initialDualSolve

        Parameter Tuple for Reliability Branching
        rel_param = (eta_rel,gamma,mu,lambda):
            eta_rel = 0       - psesudocost branching
            eta_rel = 1       - psesudocost branching with strong branching initialization
            eta_rel = 4,8     - best performing reliability branching rules
            eta_rel = inifity - strong branching
            gamma             - max number of simplex iterations in score calculation
            mu                - score factor, a number between 0 and 1. Paper uses 1/6
            lambda            - if max score is not updated for lambda 
                                consecutive iterations, stop.
        more_return:
            False - return maximizer and max 
            True  - also return a dict of stats(time, tree size, LP solved)
    """
    ACTUAL_BRANCH_STRATEGY = branch_strategy
    # reliability branching parameters
    eta_rel, gamma, mu, lam = rel_param
    # hybrid branching parameters
    total_num_pivot = average_num_pivot = 0
    # translate problems into cylp format
    cyOBJ = CyLPArray([-val for val in OBJ.values()])
    cyMAT = np.matrix([MAT[v] for v in VARIABLES]).T
    cyRHS = CyLPArray(RHS)
    OBJ = cyOBJ
    MAT = cyMAT
    RHS = cyRHS
    if T.get_layout() == 'dot2tex':
        cluster_attrs = {'name': 'Key', 'label': r'\text{Key}', 'fontsize': '12'}
        T.add_node('C', label=r'\text{Candidate}', style='filled',
                   color='yellow', fillcolor='yellow')
        T.add_node('I', label=r'\text{Infeasible}', style='filled',
                   color='orange', fillcolor='orange')
        T.add_node('S', label=r'\text{Solution}', style='filled',
                   color='lightblue', fillcolor='lightblue')
        T.add_node('P', label=r'\text{Pruned}', style='filled',
                   color='red', fillcolor='red')
        T.add_node('PC', label=r'\text{Pruned}$\\ $\text{Candidate}', style='filled',
                   color='red', fillcolor='yellow')
    else:
        cluster_attrs = {'name': 'Key', 'label': 'Key', 'fontsize': '12'}
        T.add_node('C', label='Candidate', style='filled',
                   color='yellow', fillcolor='yellow')
        T.add_node('I', label='Infeasible', style='filled',
                   color='orange', fillcolor='orange')
        T.add_node('S', label='Solution', style='filled',
                   color='lightblue', fillcolor='lightblue')
        T.add_node('P', label='Pruned', style='filled',
                   color='red', fillcolor='red')
        T.add_node('PC', label='Pruned \n Candidate', style='filled',
                   color='red', fillcolor='yellow')
    T.add_edge('C', 'I', style='invisible', arrowhead='none')
    T.add_edge('I', 'S', style='invisible', arrowhead='none')
    T.add_edge('S', 'P', style='invisible', arrowhead='none')
    T.add_edge('P', 'PC', style='invisible', arrowhead='none')
    T.create_cluster(['C', 'I', 'S', 'P', 'PC'], cluster_attrs)
    # The initial lower bound
    LB = -INFINITY
    # The number of LP's solved, and the number of nodes solved
    node_count = 1
    iter_count = 0
    lp_count = 0  # The problems that are fully solved during
    # Reliability and Hybrid branching is also couned here
    # For reliability branching
    half_solved = 0  # record number problems been halfly solved when calculate scores
    full_solved = 0  # record number problems been fully solved when calculate scores

    numVars = len(VARIABLES)
    # List of incumbent solution variable values
    opt = dict([(i, 0) for i in range(len(VARIABLES))])
    pseudo_u = dict((i, (-OBJ[i], 0)) for i in range(len(VARIABLES)))
    pseudo_d = dict((i, (-OBJ[i], 0)) for i in range(len(VARIABLES)))

    print("===========================================")
    print("Starting Branch and Bound")
    if branch_strategy == MOST_FRACTIONAL:
        print("Most fractional variable")
    elif branch_strategy == FIXED_BRANCHING:
        print("Fixed order")
    elif branch_strategy == PSEUDOCOST_BRANCHING:
        print("Pseudocost brancing")
    elif branch_strategy == RELIABILITY_BRANCHING:
        print("Reliability branching")
    elif branch_strategy == HYBRID:
        print('Hybrid strong/pseduocost branching')
    else:
        print("Unknown branching strategy %s" % branch_strategy)
    if search_strategy == DEPTH_FIRST:
        print("Depth first search strategy")
    elif search_strategy == BEST_FIRST:
        print("Best first search strategy")
    elif search_strategy == BEST_ESTIMATE:
        print("Best estimate search strategy")
    else:
        print("Unknown search strategy %s" % search_strategy)
    print("===========================================")
    # List of candidate nodes
    Q = PriorityQueue()
    # The current tree depth
    cur_depth = 0
    cur_index = 0
    # Timer
    timer = time.time()
    Q.push(0, -INFINITY, (0, None, None, None, None, None, None))
    # Branch and Bound Loop
    while not Q.isEmpty():
        # maximum allowed strong branch performed
        if branch_strategy == HYBRID and cur_depth > max(int(len(VARIABLES) * 0.2), 5):
            branch_strategy = PSEUDOCOST_BRANCHING
            print("Switch from strong branch to psedocost branch")
        infeasible = False
        integer_solution = False
        (cur_index, parent, relax, branch_var, branch_var_value, sense,
         rhs) = Q.pop()
        if cur_index is not 0:
            cur_depth = T.get_node_attr(parent, 'level') + 1
        else:
            cur_depth = 0
        print("")
        print("----------------------------------------------------")
        print("")
        if LB > -INFINITY:
            print("Node: %s, Depth: %s, LB: %s" % (cur_index, cur_depth, LB))
        else:
            print("Node: %s, Depth: %s, LB: %s" % (cur_index, cur_depth, "None"))
        if relax is not None and relax <= LB:
            print("Node pruned immediately by bound")
            T.set_node_attr(parent, 'color', 'red')
            continue
        # ====================================
        #    LP Relaxation
        # ====================================
        # Compute lower bound by LP relaxation
        prob = CyLPModel()
        if binary_vars:
            x = prob.addVariable('x', dim=len(VARIABLES))
            prob += 0 <= x <= 1
        else:
            x = prob.addVariable('x', dim=len(VARIABLES))
        prob.objective = OBJ * x
        prob += MAT * x <= RHS
        # Fix all prescribed variables
        branch_vars = []
        if cur_index is not 0:
            sys.stdout.write("Branching variables: ")
            branch_vars.append(branch_var)
            if sense == '>=':
                prob += x[branch_var] >= rhs
            else:
                prob += x[branch_var] <= rhs
            print('x_{}'.format(branch_var), end=' ')
            pred = parent
            while not str(pred) == '0':
                pred_branch_var = T.get_node_attr(pred, 'branch_var')
                pred_rhs = T.get_node_attr(pred, 'rhs')
                pred_sense = T.get_node_attr(pred, 'sense')
                if pred_sense == '<=':
                    prob += x[pred_branch_var] <= pred_rhs
                else:
                    prob += x[pred_branch_var] >= pred_rhs
                print(pred_branch_var, end=' ')
                branch_vars.append(pred_branch_var)
                pred = T.get_node_attr(pred, 'parent')
            print()
        # Solve the LP relaxation
        s = CyClpSimplex(prob)
        if solver == 'primalSimplex':
            s.initialPrimalSolve()
        elif solver == 'dualSimplex':
            s.initialDualSolve()
        else:
            s.initialSolve()
        lp_count = lp_count + 1
        total_num_pivot += s.iteration
        average_num_pivot = total_num_pivot / lp_count
        # Check infeasibility
        # -1 - unknown e.g. before solve or if postSolve says not optimal
        # 0 - optimal
        # 1 - primal infeasible
        # 2 - dual infeasible
        # 3 - stopped on iterations or time
        # 4 - stopped due to errors
        # 5 - stopped by event handler (virtual int ClpEventHandler::event())
        infeasible = (s.getStatusCode() in [1, 2])
        # Print status
        if infeasible:
            print("LP Solved, status: Infeasible")
        else:
            print("LP Solved, status: %s, obj: %s" % (s.getStatusString(),
                                                      s.objectiveValue))
        if(s.getStatusCode() == 0):
            relax = -round(s.objectiveValue,7)
            # Update pseudocost
            if branch_var != None:
                if sense == '<=':
                    pseudo_d[branch_var] = (
                        old_div((pseudo_d[branch_var][0] * pseudo_d[branch_var][1] +
                                 old_div((T.get_node_attr(parent, 'obj') - relax),
                                         (branch_var_value - rhs))),
                                (pseudo_d[branch_var][1] + 1)),
                        pseudo_d[branch_var][1] + 1)
                else:
                    pseudo_u[branch_var] = (
                        old_div((pseudo_u[branch_var][0] * pseudo_d[branch_var][1] +
                                 old_div((T.get_node_attr(parent, 'obj') - relax),
                                         (rhs - branch_var_value))),
                                (pseudo_u[branch_var][1] + 1)),
                        pseudo_u[branch_var][1] + 1)
            var_values = dict([(i, round(s.primalVariableSolution['x'][i],7))
                               for i in range(len(VARIABLES))])
            integer_solution = 1
            for i in range(len(VARIABLES)):
                if (abs(round(var_values[i]) - var_values[i]) > .001):
                    integer_solution = 0
                    break
            # Determine integer_infeasibility_count and
            # Integer_infeasibility_sum for scatterplot and such
            integer_infeasibility_count = 0
            integer_infeasibility_sum = 0.0
            for i in range(len(VARIABLES)):
                if (var_values[i] not in set([0, 1])):
                    integer_infeasibility_count += 1
                    integer_infeasibility_sum += min([var_values[i],
                                                      1.0 - var_values[i]])
            if (integer_solution and relax > LB):
                LB = relax
                for i in range(len(VARIABLES)):
                    # These two have different data structures first one
                    # list, second one dictionary
                    opt[i] = var_values[i]
                print("New best solution found, objective: %s" % relax)
                for i in range(len(VARIABLES)):
                    if var_values[i] > 0:
                        print("%s = %s" % (i, var_values[i]))
            elif (integer_solution and relax <= LB):
                print("New integer solution found, objective: %s" % relax)
                for i in range(len(VARIABLES)):
                    if var_values[i] > 0:
                        print("%s = %s" % (i, var_values[i]))
            else:
                print("Fractional solution:")
                for i in range(len(VARIABLES)):
                    if var_values[i] > 0:
                        print("x%s = %s" % (i, var_values[i]))
            # For complete enumeration
            if complete_enumeration:
                relax = LB - 1
        else:
            relax = INFINITY
        if integer_solution:
            print("Integer solution")
            BBstatus = 'S'
            status = 'integer'
            color = 'lightblue'
        elif infeasible:
            print("Infeasible node")
            BBstatus = 'I'
            status = 'infeasible'
            color = 'orange'
        elif not complete_enumeration and relax <= LB:
            print("Node pruned by bound (obj: %s, UB: %s)" % (relax, LB))
            BBstatus = 'P'
            status = 'fathomed'
            color = 'red'
        elif cur_depth >= numVars:
            print("Reached a leaf")
            BBstatus = 'fathomed'
            status = 'L'
        else:
            BBstatus = 'C'
            status = 'candidate'
            color = 'yellow'
        if BBstatus is 'I':
            if T.get_layout() == 'dot2tex':
                label = '\text{I}'
            else:
                label = 'I'
        else:
            label = "%.1f" % relax
        if iter_count == 0:
            if status is not 'candidate':
                integer_infeasibility_count = None
                integer_infeasibility_sum = None
            if status is 'fathomed':
                if T._incumbent_value is None:
                    print('WARNING: Encountered "fathom" line before ' +
                          'first incumbent.')
            T.AddOrUpdateNode(0, None, None, 'candidate', relax,
                              integer_infeasibility_count,
                              integer_infeasibility_sum,
                              label=label,
                              obj=relax, color=color,
                              style='filled', fillcolor=color)
            if status is 'integer':
                T._previous_incumbent_value = T._incumbent_value
                T._incumbent_value = relax
                T._incumbent_parent = -1
                T._new_integer_solution = True
    #           #Currently broken
    #           if ETREE_INSTALLED and T.attr['display'] == 'svg':
    #               T.write_as_svg(filename = "node%d" % iter_count,
    #                                 nextfile = "node%d" % (iter_count + 1),
    #                                 highlight = cur_index)
        else:
            _direction = {'<=': 'L', '>=': 'R'}
            if status is 'infeasible':
                integer_infeasibility_count = T.get_node_attr(parent,
                                                              'integer_infeasibility_count')
                integer_infeasibility_sum = T.get_node_attr(parent,
                                                            'integer_infeasibility_sum')
                relax = T.get_node_attr(parent, 'lp_bound')
            elif status is 'fathomed':
                if T._incumbent_value is None:
                    print('WARNING: Encountered "fathom" line before' +
                          ' first incumbent.')
                    print('  This may indicate an error in the input file.')
            elif status is 'integer':
                integer_infeasibility_count = None
                integer_infeasibility_sum = None
            T.AddOrUpdateNode(cur_index, parent, _direction[sense],
                              status, relax,
                              integer_infeasibility_count,
                              integer_infeasibility_sum,
                              branch_var=branch_var,
                              branch_var_value=var_values[branch_var],
                              sense=sense, rhs=rhs, obj=relax,
                              color=color, style='filled',
                              label=label, fillcolor=color)
            if status is 'integer':
                T._previous_incumbent_value = T._incumbent_value
                T._incumbent_value = relax
                T._incumbent_parent = parent
                T._new_integer_solution = True
            # Currently Broken
    #           if ETREE_INSTALLED and T.attr['display'] == 'svg':
    #               T.write_as_svg(filename = "node%d" % iter_count,
    #                                 prevfile = "node%d" % (iter_count - 1),
    #                                 nextfile = "node%d" % (iter_count + 1),
    #                                 highlight = cur_index)
            if T.get_layout() == 'dot2tex':
                _dot2tex_label = {'>=': ' \geq ', '<=': ' \leq '}
                T.set_edge_attr(parent, cur_index, 'label',
                                str(branch_var) + _dot2tex_label[sense] +
                                str(rhs))
            else:
                T.set_edge_attr(parent, cur_index, 'label',
                                str(branch_var) + sense + str(rhs))
        iter_count += 1
        if BBstatus == 'C':
            # Branching:
            # Choose a variable for branching
            branching_var = None
            if branch_strategy == FIXED_BRANCHING:
                # fixed order
                for i in range(len(VARIABLES)):
                    frac = min(var_values[i] - math.floor(var_values[i]),
                               math.ceil(var_values[i]) - var_values[i])
                    if (frac > 0):
                        min_frac = frac
                        branching_var = i
                        # TODO(aykut): understand this break
                        break
            elif branch_strategy == MOST_FRACTIONAL:
                # most fractional variable
                min_frac = -1
                for i in range(len(VARIABLES)):
                    frac = min(var_values[i] - math.floor(var_values[i]),
                               math.ceil(var_values[i]) - var_values[i])
                    if (frac > min_frac):
                        min_frac = frac
                        branching_var = i
            elif branch_strategy == PSEUDOCOST_BRANCHING:
                scores = {}
                for i in range(len(VARIABLES)):
                    # find the fractional solutions
                    if abs(var_values[i] - math.floor(var_values[i])) > 1e-8:
                        scores[i] = min(pseudo_u[i][0] * (math.ceil(var_values[i])
                                                          - var_values[i]),
                                        pseudo_d[i][0] * (var_values[i]
                                                          - math.floor(var_values[i])))
                # sort the dictionary by value
                branching_var = sorted(list(scores.items()), key=lambda x: x[1])[-1][0]

            elif branch_strategy == RELIABILITY_BRANCHING:
                # Calculating Scores
                # The algorithm in paper is different from the one in Grumpy
                # I will try to use paper notations
                scores = {}
                for i in range(len(VARIABLES)):
                    # find the fractional solutions
                    if abs(var_values[i] - math.floor(var_values[i])) > 1e-8:
                        qp = pseudo_u[i][0] * (math.ceil(var_values[i])
                                               - var_values[i])  # q^+
                        qm = pseudo_d[i][0] * (var_values[i]
                                               - math.floor(var_values[i]))  # q^^-
                        scores[i] = (1 - mu) * min(qm, qp) + mu * max(qm, qp)

                # sort the dictionary by value
                candidate_vars = [en[0] for en in sorted(list(scores.items()), key=lambda x: x[1], reverse=True)]

                no_change = 0  # number of iterations that maximum of scores is not changed
                smax = scores[candidate_vars[0]]  # current maximum of scores
                for i in candidate_vars:
                    if min(pseudo_d[i][1], pseudo_u[i][1]) < eta_rel:
                        qp = pseudo_u[i][0] * (math.ceil(var_values[i]) - var_values[i])  # q^+
                        qm = pseudo_d[i][0] * (var_values[i] - math.floor(var_values[i]))  # q^^-

                        # left subproblem/down direction
                        s_left = CyClpSimplex(prob)
                        s_left += x[i] <= math.floor(var_values[i])
                        s_left.maxNumIteration = gamma  # solve for fixed number of iterations
                        s_left.dual()
                        if s_left.getStatusCode() == 0:
                            qm = relax + s_left.objectiveValue  # use a more reliable source to update q^-
                            full_solved = full_solved + 1
                            lp_count = lp_count + 1  # If the LP is fully solved, counter plus one
                        elif s_left.getStatusCode() == 3:
                            qm = relax + s_left.objectiveValue  # use a more reliable source to update q^-
                            half_solved = half_solved + 1

                        # right subproblem/up direction
                        s_right = CyClpSimplex(prob)
                        s_right += x[i] >= math.ceil(var_values[i])
                        s_right.maxNumIteration = gamma  # solve for fixed number of iterations
                        s_right.dual()
                        if s_right.getStatusCode() == 0:
                            qp = relax + s_right.objectiveValue   # use a more reliable source to update q^+
                            full_solved = full_solved + 1
                            lp_count = lp_count + 1  # If the LP is fully solved, counter plus one
                        elif s_right.getStatusCode() == 3:
                            qp = relax + s_right.objectiveValue  # use a more reliable source to update q^+
                            half_solved = half_solved + 1

                        scores[i] = (1 - mu) * min(qm, qp) + mu * max(qm, qp)
                        if (smax == scores[i]):
                            no_change += 1
                        elif (smax <= scores[i]):
                            no_change = 0
                            smax = scores[i]
                        else:
                            no_change = 0

                    if no_change >= lam:
                        break
                branching_var = sorted(list(scores.items()), key=lambda x: x[1])[-1][0]

            elif branch_strategy == HYBRID:
                scores = {}
                for i in range(len(VARIABLES)):
                    # find the fractional solutions
                    if abs(var_values[i] - math.floor(var_values[i])) > 1e-8:
                        scores[i] = min(pseudo_u[i][0] * (math.ceil(var_values[i])
                                                          - var_values[i]),
                                        pseudo_d[i][0] * (var_values[i]
                                                          - math.floor(var_values[i])))
                candidate_vars = [en[0] for en in sorted(list(scores.items()), key=lambda x: x[1], reverse=True)]
                restricted_candidate_vars = candidate_vars[:max(1, int(0.5 * len(candidate_vars)))]
                # print("Subset of candidate variables:")
                # print(restricted_candidate_vars)
                best_progress = 0
                branch_candidate = None
                for i in restricted_candidate_vars:
                    s = CyClpSimplex(prob)
                    s += math.floor(var_values[i]) <= x[i] <= math.ceil(var_values[i])
                    s.maxNumIteration = average_num_pivot * 2
                    s.dual()
                    if s.getStatusCode() == 0:
                        lp_count += 1
                    progress = relax - (-s.objectiveValue)
                    if (progress - best_progress) > 1e-8:
                        branch_candidate = i
                        best_progress = progress
                if branch_candidate is None:
                    branch_candidate = restricted_candidate_vars[0]
                branching_var = branch_candidate

            else:
                print("Unknown branching strategy %s" % branch_strategy)
                exit()
            if branching_var is not None:
                print("Branching on variable %s" % branching_var)
            # Create new nodes
            if search_strategy == DEPTH_FIRST:
                priority = (-cur_depth - 1, -cur_depth - 1)
            elif search_strategy == BEST_FIRST:
                priority = (-relax, -relax)
            elif search_strategy == BEST_ESTIMATE:
                priority = (-relax - pseudo_d[branching_var][0] *
                            (math.floor(var_values[branching_var]) - var_values[branching_var]),
                            -relax + pseudo_u[branching_var][0] *
                            (math.ceil(var_values[branching_var]) - var_values[branching_var]))
            node_count += 1
            Q.push(node_count, priority[0], (node_count, cur_index, relax, branching_var,
                                             var_values[branching_var],
                                             '<=', math.floor(var_values[branching_var])))
            node_count += 1
            Q.push(node_count, priority[1], (node_count, cur_index, relax, branching_var,
                                             var_values[branching_var],
                                             '>=', math.ceil(var_values[branching_var])))
            T.set_node_attr(cur_index, color, 'green')
        if T.root is not None and display_interval is not None and\
                iter_count % display_interval == 0:
            T.display(count=iter_count)

    timer = int(math.ceil((time.time() - timer) * 1000))
    print("")
    print("===========================================")
    print("Branch and bound completed in %sms" % timer)
    print("Strategy: %s" % ACTUAL_BRANCH_STRATEGY)
    if complete_enumeration:
        print("Complete enumeration")
    print("%s nodes visited " % node_count)
    print("%s LP's solved" % lp_count)
    print("===========================================")
    print("Optimal solution")
    # print optimal solution
    for i in range(len(VARIABLES)):
        if opt[i] > 0:
            print("x%s = %s" % (i, opt[i]))
    print("Objective function value")
    print(LB)
    print("===========================================")
    if T.attr['display'] is not 'off':
        T.display(count=iter_count)
    T._lp_count = lp_count

    if more_return:
        stat = {'Time': timer, 'Size': node_count, 'LP Solved': lp_count}
        if branch_strategy == RELIABILITY_BRANCHING:
            stat['LP Solved for Bounds'] = lp_count - full_solved
            stat['Halfly Solved'] = half_solved
            stat['Fully Solved'] = full_solved
        return opt, LB, stat
    
    return opt, LB
Example #20
0
def Single_Year_Stage_II(puf, Stage_I_factors, Stage_II_targets, year, tol):


    length = len(puf.s006)


    print("Preparing coefficient matrix...")

    s006 = np.where(puf.e02400>0,
                    puf.s006*Stage_I_factors[year]["APOPSNR"]/100,
                    puf.s006*Stage_I_factors[year]["ARETS"]/100)



    single_return = np.where(puf.mars==1, s006, 0)
    joint_return = np.where((puf.mars==2)|(puf.mars==3), s006, 0)
    hh_return = np.where(puf.mars==4,s006,0)
    return_w_SS = np.where(puf.e02400>0,s006,0)

    dependent_exempt_num = (puf.xocah+puf.xocawh+puf.xoodep+puf.xopar)*s006
    interest = puf.e00300*s006
    dividend = puf.e00600*s006
    biz_income = np.where(puf.e00900>0, puf.e00900, 0)*s006
    biz_loss = np.where(puf.e00900<0, -puf.e00900, 0)*s006
    cap_gain = np.where(puf.e01000>0, puf.e01000, 0)*s006
    annuity_pension = puf.e01700*s006
    sch_e_income = np.where(puf.e02000>0, puf.e02000, 0)*s006
    sch_e_loss = np.where(puf.e02000<0, -puf.e02000, 0)*s006
    ss_income = puf.e02400*s006
    unemployment_comp = puf.e02300*s006


    # Wage distribution

    wage_1 = np.where(puf.e00100<=0, puf.e00200,0)*s006
    wage_2 = np.where((puf.e00100>0)&(puf.e00100<=10000), puf.e00200,0)*s006
    wage_3 = np.where((puf.e00100>10000)&(puf.e00100<=20000), puf.e00200,0)*s006
    wage_4 = np.where((puf.e00100>20000)&(puf.e00100<=30000), puf.e00200,0)*s006
    wage_5 = np.where((puf.e00100>30000)&(puf.e00100<=40000), puf.e00200,0)*s006
    wage_6 = np.where((puf.e00100>40000)&(puf.e00100<=50000), puf.e00200,0)*s006
    wage_7 = np.where((puf.e00100>50000)&(puf.e00100<=75000), puf.e00200,0)*s006
    wage_8 = np.where((puf.e00100>75000)&(puf.e00100<=100000), puf.e00200,0)*s006
    wage_9 = np.where((puf.e00100>100000)&(puf.e00100<=200000), puf.e00200,0)*s006
    wage_10 = np.where((puf.e00100>200000)&(puf.e00100<=500000), puf.e00200,0)*s006
    wage_11 = np.where((puf.e00100>500000)&(puf.e00100<=1000000), puf.e00200,0)*s006
    wage_12 = np.where((puf.e00100>1000000), puf.e00200,0)*s006


    # Set up the matrix
    One_half_LHS = np.vstack((single_return, joint_return, hh_return, return_w_SS,
                              dependent_exempt_num, interest, dividend,
                              biz_income,biz_loss, cap_gain, annuity_pension,
                              sch_e_income, sch_e_loss, ss_income, unemployment_comp,
                              wage_1, wage_2, wage_3, wage_4, wage_5, wage_6,
                              wage_7, wage_8, wage_9, wage_10, wage_11, wage_12))


    # Coefficients for r and s
    A1 = np.matrix(One_half_LHS)
    A2 = np.matrix(-One_half_LHS)


    print("Preparing targets for ", year)

    APOPN = Stage_I_factors[year]["APOPN"]

    b = []

    b.append(Stage_II_targets[year]['Single']-single_return.sum())
    b.append(Stage_II_targets[year]['Joint']-joint_return.sum())
    b.append(Stage_II_targets[year]['HH']-hh_return.sum())
    b.append(Stage_II_targets[year]['SS_return']-return_w_SS.sum())

    b.append(Stage_II_targets[year]['Dep_return'] -  dependent_exempt_num.sum())

    AINTS = Stage_I_factors[year]["AINTS"]
    INTEREST = Stage_II_targets[year]['INTS']*APOPN/AINTS*1000-interest.sum()

    ADIVS = Stage_I_factors[year]["ADIVS"]
    DIVIDEND = Stage_II_targets[year]['DIVS']*APOPN/ADIVS*1000 - dividend.sum()

    ASCHCI = Stage_I_factors[year]["ASCHCI"]
    BIZ_INCOME = Stage_II_targets[year]['SCHCI']*APOPN/ASCHCI*1000 - biz_income.sum()


    ASCHCL = Stage_I_factors[year]["ASCHCL"]
    BIZ_LOSS = Stage_II_targets[year]['SCHCL']*APOPN/ASCHCL*1000 - biz_loss.sum()

    ACGNS = Stage_I_factors[year]["ACGNS"]
    CAP_GAIN = Stage_II_targets[year]['CGNS']*APOPN/ACGNS*1000 - cap_gain.sum()

    ATXPY = Stage_I_factors[year]["ATXPY"]
    ANNUITY_PENSION = Stage_II_targets[year]['Pension']*APOPN/ATXPY*1000 - annuity_pension.sum()

    ASCHEI = Stage_I_factors[year]["ASCHEI"]
    SCH_E_INCOME = Stage_II_targets[year]["SCHEI"]*APOPN/ASCHEI*1000 - sch_e_income.sum()

    ASCHEL = Stage_I_factors[year]["ASCHEL"]
    SCH_E_LOSS = Stage_II_targets[year]["SCHEL"]*APOPN/ASCHEL*1000 - sch_e_loss.sum()

    ASOCSEC = Stage_I_factors[year]["ASOCSEC"]
    APOPSNR = Stage_I_factors[year]["APOPSNR"]
    SS_INCOME = Stage_II_targets[year]["SS"]*APOPSNR/ASOCSEC*1000 - ss_income.sum()

    AUCOMP = Stage_I_factors[year]["AUCOMP"]
    UNEMPLOYMENT_COMP = Stage_II_targets[year]["UCOMP"]*APOPN/AUCOMP*1000 - unemployment_comp.sum()

    AWAGE = Stage_I_factors[year]["AWAGE"]
    WAGE_1 = Stage_II_targets[year]["WAGE_1"]*APOPN/AWAGE*1000 - wage_1.sum()
    WAGE_2 = Stage_II_targets[year]["WAGE_2"]*APOPN/AWAGE*1000 - wage_2.sum()
    WAGE_3 = Stage_II_targets[year]["WAGE_3"]*APOPN/AWAGE*1000 - wage_3.sum()
    WAGE_4 = Stage_II_targets[year]["WAGE_4"]*APOPN/AWAGE*1000 - wage_4.sum()
    WAGE_5 = Stage_II_targets[year]["WAGE_5"]*APOPN/AWAGE*1000 - wage_5.sum()
    WAGE_6 = Stage_II_targets[year]["WAGE_6"]*APOPN/AWAGE*1000 - wage_6.sum()
    WAGE_7 = Stage_II_targets[year]["WAGE_7"]*APOPN/AWAGE*1000 - wage_7.sum()
    WAGE_8 = Stage_II_targets[year]["WAGE_8"]*APOPN/AWAGE*1000 - wage_8.sum()
    WAGE_9 = Stage_II_targets[year]["WAGE_9"]*APOPN/AWAGE*1000 - wage_9.sum()
    WAGE_10 = Stage_II_targets[year]["WAGE_10"]*APOPN/AWAGE*1000 - wage_10.sum()
    WAGE_11 = Stage_II_targets[year]["WAGE_11"]*APOPN/AWAGE*1000 - wage_11.sum()
    WAGE_12 = Stage_II_targets[year]["WAGE_12"]*APOPN/AWAGE*1000 - wage_12.sum()



    temp = [INTEREST,DIVIDEND, BIZ_INCOME, BIZ_LOSS, CAP_GAIN, ANNUITY_PENSION, SCH_E_INCOME, SCH_E_LOSS, SS_INCOME, UNEMPLOYMENT_COMP,
            WAGE_1,WAGE_2, WAGE_3,WAGE_4, WAGE_5, WAGE_6, WAGE_7,WAGE_8,WAGE_9, WAGE_10, WAGE_11, WAGE_12]
    for m in temp:
        b.append(m)

    targets = CyLPArray(b)
    print("Targets for year ", year, " is ", targets)

    LP = CyLPModel()

    r = LP.addVariable('r', length)
    s = LP.addVariable('s', length)

    print("Adding constraints")
    LP.addConstraint(r >=0, "positive r")
    LP.addConstraint(s >=0, "positive s")
    LP.addConstraint(r + s <= tol, "abs upperbound")

    c = CyLPArray((np.ones(length)))
    LP.objective = c * r + c * s




    LP.addConstraint(A1 * r + A2 * s == targets, "Aggregates")

    print("Setting up the LP model")
    model = CyClpSimplex(LP)


    print("Solving LP......")
    model.initialSolve()

    print("DONE!!")
    z = np.empty([length])
    z = (1+model.primalVariableSolution['r'] - model.primalVariableSolution['s'])*s006
    return z
Example #21
0
def get_model_quality_estimate_clp(settings, n, k, node_pos, node_val,
                                   num_iterations):
    """Compute an estimate of model quality using LPs with Clp.

    Computes an estimate of model quality, performing
    cross-validation. This version does not use all interpolation
    nodes, but rather only the best num_iterations ones, and it uses a
    sequence of LPs instead of a brute-force calculation. It should be
    much faster than the brute-force calculation, as each LP in the
    sequence requires only two pivots. The solver is COIN-OR Clp.

    Parameters
    ----------
    settings : :class:`rbfopt_settings.RbfSettings`
        Global and algorithmic settings.

    n : int
        Dimension of the problem, i.e. the space where the point lives.

    k : int
        Number of nodes, i.e. interpolation points.

    node_pos : 2D numpy.ndarray[float]
        Location of current interpolation nodes (one on each row).

    node_val : 1D numpy.ndarray[float]
        List of values of the function at the nodes.

    num_iterations : int
        Number of nodes on which quality should be tested.
    
    Returns
    -------
    float
        An estimate of the leave-one-out cross-validation error, which
        can be interpreted as a measure of model quality.

    Raises
    ------
    RuntimeError
        If the LPs cannot be solved.

    ValueError
        If some settings are not supported.
    """
    assert(isinstance(node_pos, np.ndarray))
    assert(isinstance(node_val, np.ndarray))
    assert(isinstance(settings, RbfSettings))
    assert(len(node_val) == k)
    assert(len(node_pos) == k)
    assert(num_iterations <= k)
    assert(cpx_available)
    # We cannot find a leave-one-out interpolant if the following
    # condition is not met.
    assert(k > n + 1)

    # Get size of polynomial part of the matrix (p) and sign of obj
    # function (sign)
    if (ru.get_degree_polynomial(settings) == 1):
        p = n + 1
        sign = 1
    elif (ru.get_degree_polynomial(settings) == 0):
        p = 1
        sign = -1
    else:
        raise ValueError('RBF type ' + settings.rbf + ' not supported')

    # Sort interpolation nodes by increasing objective function value
    sorted_idx = node_val.argsort()

    # Initialize the arrays used for the cross-validation
    cv_node_pos = node_pos[sorted_idx]
    cv_node_val = node_val[sorted_idx]

    # Compute the RBF matrix, and the two submatrices of interest
    Amat = ru.get_rbf_matrix(settings, n, k, cv_node_pos)
    Phimat = Amat[:k, :k]
    Pmat = Amat[:k, k:]
    identity = np.matrix(np.identity(k))

    # Instantiate model
    model = CyLPModel()

    # Add variables: lambda, h, slacks
    rbf_lambda = model.addVariable('rbf_lambda', k)
    rbf_h = model.addVariable('rbf_h', p)
    slack = model.addVariable('slack', k)

    # Add constraints: interpolation conditions, unisolvence
    F = CyLPArray(cv_node_val)
    zeros = CyLPArray([0] * p)
    ones = CyLPArray([1] * p)
    if (p > 1):
        # We can use matrix form
        model += (Phimat * rbf_lambda + Pmat * rbf_h + identity * slack == F)
        model += (Pmat.transpose() * rbf_lambda == zeros)
    else:
        # Workaround for one dimensional variables: one row at a time
        for i in range(k):
            model += Phimat[i, :] * rbf_lambda + rbf_h + slack[i] == F[i]
        model += (Pmat.transpose() * rbf_lambda == zeros)

    # Add objective
    obj = CyLPArray([sign*val for val in node_val])
    model.objective = obj * rbf_lambda
                           
    # Create LP, suppress output, and set bounds
    lp = clp.CyClpSimplex(model)
    lp.logLevel = 0
    infinity = lp.getCoinInfinity()
    for i in range(k + p):
        lp.setColumnLower(i, -infinity)
        lp.setColumnUpper(i, infinity)
    for i in range(k):
        lp.setColumnLower(k + p + i, 0.0)
        lp.setColumnUpper(k + p + i, 0.0)

    # Estimate of the model error
    loo_error = 0.0

    for i in range(num_iterations):
        # Fix lambda[i] to zero
        lp.setColumnLower(i, 0.0)
        lp.setColumnUpper(i, 0.0)
        # Set slack[i] to unconstrained
        lp.setColumnLower(k + p + i, -infinity)
        lp.setColumnUpper(k + p + i, infinity)

        lp.dual(startFinishOptions = 'sx')

        if (not lp.getStatusCode() == 0):
            raise RuntimeError('Could not solve LP with Clp, status ' +
                               lp.getStatusString())

        lambda_sol = lp.primalVariableSolution['rbf_lambda'].tolist()
        h_sol = lp.primalVariableSolution['rbf_h'].tolist()

        # Compute value of the interpolant at the removed node
        predicted_val = ru.evaluate_rbf(settings, cv_node_pos[i], n, k,
                                        cv_node_pos, lambda_sol, h_sol)

        # Update leave-one-out error
        loo_error += abs(predicted_val - cv_node_val[i])

        # Fix lambda[i] to zero
        lp.setColumnLower(i, -infinity)
        lp.setColumnUpper(i, infinity)
        # Set slack[i] to unconstrained
        lp.setColumnLower(k + p + i, 0.0)
        lp.setColumnUpper(k + p + i, 0.0)

    return loo_error/num_iterations
Example #22
0
def LP_solver_cylp_mp(A_Matrix, B_vectors, weights, really_verbose=False,
                      proc=1):
    """
    Solve the Linear Programming problem given in Giangrande et al, 2012 using
    the CyLP module using multiple processes.

    Parameters
    ----------
    A_Matrix : matrix
        Row augmented A matrix, see :py:func:`construct_A_matrix`
    B_vectors : matrix
        Matrix containing B vectors, see :py:func:`construct_B_vectors`
    weights : array
        Weights.
    really_verbose : bool
        True to print CLP messaging. False to suppress.
    proc : int
        Number of worker processes.

    Returns
    -------
    soln : array
        Solution to LP problem.

    See Also
    --------
    LP_solver_cvxopt : Solve LP problem using the CVXOPT module.
    LP_solver_pyglpk : Solve LP problem using the PyGLPK module.
    LP_solver_cylp : Solve LP problem using the CyLP module using single
                     process.

    """
    from cylp.cy.CyClpSimplex import CyClpSimplex
    from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray
    import multiprocessing as mp

    n_gates = weights.shape[1] // 2
    n_rays = B_vectors.shape[0]
    soln = np.zeros([n_rays, n_gates])

    # Create CyLPModel and initialize it
    model = CyLPModel()
    G = np.matrix(A_Matrix)
    h = CyLPArray(np.empty(B_vectors.shape[1]))
    x = model.addVariable('x', G.shape[1])
    model.addConstraint(G * x >= h)
    c = CyLPArray(np.empty(weights.shape[1]))
    #c = CyLPArray(np.squeeze(weights[0]))
    model.objective = c * x

    chunksize = int(n_rays/proc)
    # check if equal sized chunks can be distributed to worker processes
    if n_rays % chunksize != 0:
        print("Problem of %d rays cannot be split to %d worker processes!\n\r"
              "Fallback to 1 process!" % (n_rays, proc))
        chunksize = n_rays  # fall back to one process
        proc = 1

    print("Calculating with %d processes, %d rays per chunk" %
          (proc, chunksize))

    def worker(model, B_vectors, weights, ray, chunksize, out_q):
        """
        The worker function, invoked in a process.
        The results are placed in a dictionary that's pushed to a queue.
        """
        outdict = {}
        iray = int(ray/chunksize)
        outdict[iray] = solve_cylp(model, B_vectors, weights, ray, chunksize)
        out_q.put(outdict)

    # Queue for LP solutions
    out_q = mp.Queue()
    procs = []

    # fire off worker processes
    for raynum in range(0, n_rays, chunksize):
        p = mp.Process(target=worker, args=(
            model, B_vectors, weights, raynum, chunksize, out_q))
        procs.append(p)
        p.start()

    # collecting results
    resultdict = {}
    for raynum in range(0, n_rays, chunksize):
        resultdict.update(out_q.get())

    # Wait for all worker processes to finish
    for p in procs:
        p.join()

    # copy results in output array
    for raynum in range(0, int(n_rays / chunksize)):
        soln[raynum * chunksize:raynum * chunksize + chunksize, :] = (
            resultdict[raynum])

    # apply smoothing filter to output array
    soln = smooth_and_trim_scan(soln, window_len=5, window='sg_smooth')

    return soln
Example #23
0
def LP_solver_cylp_mp(A_Matrix,
                      B_vectors,
                      weights,
                      really_verbose=False,
                      proc=1):
    """
    Solve the Linear Programming problem given in Giangrande et al, 2012 using
    the CyLP module using multiple processes.

    Parameters
    ----------
    A_Matrix : matrix
        Row augmented A matrix, see :py:func:`construct_A_matrix`
    B_vectors : matrix
        Matrix containing B vectors, see :py:func:`construct_B_vectors`
    weights : array
        Weights.
    really_verbose : bool
        True to print CLP messaging. False to suppress.
    proc : int
        Number of worker processes.

    Returns
    -------
    soln : array
        Solution to LP problem.

    See Also
    --------
    LP_solver_cvxopt : Solve LP problem using the CVXOPT module.
    LP_solver_pyglpk : Solve LP problem using the PyGLPK module.
    LP_solver_cylp : Solve LP problem using the CyLP module using single
                     process.

    """
    from cylp.cy.CyClpSimplex import CyClpSimplex
    from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray
    import multiprocessing as mp

    n_gates = weights.shape[1] // 2
    n_rays = B_vectors.shape[0]
    soln = np.zeros([n_rays, n_gates])

    # Create CyLPModel and initialize it
    model = CyLPModel()
    G = np.matrix(A_Matrix)
    h = CyLPArray(np.empty(B_vectors.shape[1]))
    x = model.addVariable('x', G.shape[1])
    model.addConstraint(G * x >= h)
    c = CyLPArray(np.empty(weights.shape[1]))
    #c = CyLPArray(np.squeeze(weights[0]))
    model.objective = c * x

    chunksize = int(n_rays / proc)
    # check if equal sized chunks can be distributed to worker processes
    if n_rays % chunksize != 0:
        print("Problem of %d rays cannot be split to %d worker processes!\n\r"
              "Fallback to 1 process!" % (n_rays, proc))
        chunksize = n_rays  # fall back to one process
        proc = 1

    print("Calculating with %d processes, %d rays per chunk" %
          (proc, chunksize))

    def worker(model, B_vectors, weights, ray, chunksize, out_q):
        """
        The worker function, invoked in a process.
        The results are placed in a dictionary that's pushed to a queue.
        """
        outdict = {}
        iray = int(ray / chunksize)
        outdict[iray] = solve_cylp(model, B_vectors, weights, ray, chunksize)
        out_q.put(outdict)

    # Queue for LP solutions
    out_q = mp.Queue()
    procs = []

    # fire off worker processes
    for raynum in range(0, n_rays, chunksize):
        p = mp.Process(target=worker,
                       args=(model, B_vectors, weights, raynum, chunksize,
                             out_q))
        procs.append(p)
        p.start()

    # collecting results
    resultdict = {}
    for raynum in range(0, n_rays, chunksize):
        resultdict.update(out_q.get())

    # Wait for all worker processes to finish
    for p in procs:
        p.join()

    # copy results in output array
    for raynum in range(0, int(n_rays / chunksize)):
        soln[raynum * chunksize:raynum * chunksize +
             chunksize, :] = (resultdict[raynum])

    # apply smoothing filter to output array
    soln = smooth_and_trim_scan(soln, window_len=5, window='sg_smooth')

    return soln
Example #24
0
def solve_lp_for_year(puf, Stage_I_factors, Stage_II_targets, year, tol):

    puf_length = len(puf.s006)

    print("Preparing coefficient matrix for year {} .....".format(year))

    s006 = np.where(puf.e02400 > 0,
                    puf.s006 * Stage_I_factors[year]["APOPSNR"] / 100,
                    puf.s006 * Stage_I_factors[year]["ARETS"] / 100)

    single_return = np.where((puf.mars == 1) & (puf.filer == 1), s006, 0)
    joint_return = np.where(
        ((puf.mars == 2) | (puf.mars == 3)) & (puf.filer == 1), s006, 0)
    hh_return = np.where((puf.mars == 4) & (puf.filer == 1), s006, 0)
    return_w_SS = np.where((puf.e02400 > 0) & (puf.filer == 1), s006, 0)

    dependent_exempt_num = (puf.xocah + puf.xocawh + puf.xoodep +
                            puf.xopar) * s006
    interest = puf.e00300 * s006
    dividend = puf.e00600 * s006
    biz_income = np.where(puf.e00900 > 0, puf.e00900, 0) * s006
    biz_loss = np.where(puf.e00900 < 0, -puf.e00900, 0) * s006
    cap_gain = np.where(
        (puf.p23250 + puf.p22250) > 0, puf.p23250 + puf.p22250, 0) * s006
    annuity_pension = puf.e01700 * s006
    sch_e_income = np.where(puf.e02000 > 0, puf.e02000, 0) * s006
    sch_e_loss = np.where(puf.e02000 < 0, -puf.e02000, 0) * s006
    ss_income = np.where(puf.filer == 1, puf.e02400, 0) * s006
    unemployment_comp = puf.e02300 * s006

    # Wage distribution
    wage_1 = np.where(puf.e00100 <= 0, puf.e00200, 0) * s006
    wage_2 = np.where(
        (puf.e00100 > 0) & (puf.e00100 <= 10000), puf.e00200, 0) * s006
    wage_3 = np.where(
        (puf.e00100 > 10000) & (puf.e00100 <= 20000), puf.e00200, 0) * s006
    wage_4 = np.where(
        (puf.e00100 > 20000) & (puf.e00100 <= 30000), puf.e00200, 0) * s006
    wage_5 = np.where(
        (puf.e00100 > 30000) & (puf.e00100 <= 40000), puf.e00200, 0) * s006
    wage_6 = np.where(
        (puf.e00100 > 40000) & (puf.e00100 <= 50000), puf.e00200, 0) * s006
    wage_7 = np.where(
        (puf.e00100 > 50000) & (puf.e00100 <= 75000), puf.e00200, 0) * s006
    wage_8 = np.where(
        (puf.e00100 > 75000) & (puf.e00100 <= 100000), puf.e00200, 0) * s006
    wage_9 = np.where(
        (puf.e00100 > 100000) & (puf.e00100 <= 200000), puf.e00200, 0) * s006
    wage_10 = np.where(
        (puf.e00100 > 200000) & (puf.e00100 <= 500000), puf.e00200, 0) * s006
    wage_11 = np.where(
        (puf.e00100 > 500000) & (puf.e00100 <= 1000000), puf.e00200, 0) * s006
    wage_12 = np.where(puf.e00100 > 1000000, puf.e00200, 0) * s006

    # Set up the matrix
    One_half_LHS = np.vstack(
        (single_return, joint_return, hh_return, return_w_SS,
         dependent_exempt_num, interest, dividend, biz_income, biz_loss,
         cap_gain, annuity_pension, sch_e_income, sch_e_loss, ss_income,
         unemployment_comp, wage_1, wage_2, wage_3, wage_4, wage_5, wage_6,
         wage_7, wage_8, wage_9, wage_10, wage_11, wage_12))

    # Coefficients for r and s
    A1 = np.matrix(One_half_LHS)
    A2 = np.matrix(-One_half_LHS)

    print("Preparing targets for year {} .....".format(year))

    APOPN = Stage_I_factors[year]["APOPN"]

    b = []

    b.append(Stage_II_targets[year]["Single Returns"] - single_return.sum())
    b.append(Stage_II_targets[year]["Joint Returns"] - joint_return.sum())
    target_name = "Head of Household Returns"
    b.append(Stage_II_targets[year][target_name] - hh_return.sum())
    target_name = "Number of Returns w/ Gross Security Income"
    b.append(Stage_II_targets[year][target_name] - return_w_SS.sum())
    target_name = "Number of Dependent Exemptions"
    b.append(Stage_II_targets[year][target_name] - dependent_exempt_num.sum())

    AINTS = Stage_I_factors[year]["AINTS"]
    INTEREST = (Stage_II_targets[year]["Taxable Interest Income"] * APOPN /
                AINTS * 1000 - interest.sum())

    ADIVS = Stage_I_factors[year]["ADIVS"]
    DIVIDEND = (
        Stage_II_targets[year]["Ordinary Dividends"] * APOPN / ADIVS * 1000 -
        dividend.sum())

    ASCHCI = Stage_I_factors[year]["ASCHCI"]
    BIZ_INCOME = (Stage_II_targets[year]["Business Income (Schedule C)"] *
                  APOPN / ASCHCI * 1000 - biz_income.sum())

    ASCHCL = Stage_I_factors[year]["ASCHCL"]
    BIZ_LOSS = (Stage_II_targets[year]["Business Loss (Schedule C)"] * APOPN /
                ASCHCL * 1000 - biz_loss.sum())

    ACGNS = Stage_I_factors[year]["ACGNS"]
    CAP_GAIN = (Stage_II_targets[year]["Net Capital Gains in AGI"] * APOPN /
                ACGNS * 1000 - cap_gain.sum())

    ATXPY = Stage_I_factors[year]["ATXPY"]
    target_name = "Taxable Pensions and Annuities"
    ANNUITY_PENSION = (
        Stage_II_targets[year][target_name] * APOPN / ATXPY * 1000 -
        annuity_pension.sum())

    ASCHEI = Stage_I_factors[year]["ASCHEI"]
    target_name = "Supplemental Income (Schedule E)"
    SCH_E_INCOME = (
        Stage_II_targets[year][target_name] * APOPN / ASCHEI * 1000 -
        sch_e_income.sum())

    ASCHEL = Stage_I_factors[year]["ASCHEL"]
    SCH_E_LOSS = (Stage_II_targets[year]["Supplemental Loss (Schedule E)"] *
                  APOPN / ASCHEL * 1000 - sch_e_loss.sum())

    ASOCSEC = Stage_I_factors[year]["ASOCSEC"]
    APOPSNR = Stage_I_factors[year]["APOPSNR"]
    SS_INCOME = (Stage_II_targets[year]["Gross Social Security Income"] *
                 APOPSNR / ASOCSEC * 1000 - ss_income.sum())

    AUCOMP = Stage_I_factors[year]["AUCOMP"]
    UNEMPLOYMENT_COMP = (Stage_II_targets[year]["Unemployment Compensation"] *
                         APOPN / AUCOMP * 1000 - unemployment_comp.sum())

    AWAGE = Stage_I_factors[year]["AWAGE"]
    target_name = "Wages and Salaries: Zero or Less"
    WAGE_1 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_1.sum())
    target_name = "Wages and Salaries: $1 Less Than $10,000"
    WAGE_2 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_2.sum())
    target_name = "Wages and Salaries: $10,000 Less Than $20,000"
    WAGE_3 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_3.sum())
    target_name = "Wages and Salaries: $20,000 Less Than $30,000"
    WAGE_4 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_4.sum())
    target_name = "Wages and Salaries: $30,000 Less Than $40,000"
    WAGE_5 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_5.sum())
    target_name = "Wages and Salaries: $40,000 Less Than $50,000"
    WAGE_6 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_6.sum())
    target_name = "Wages and Salaries: $50,000 Less Than $75,000"
    WAGE_7 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_7.sum())
    target_name = "Wages and Salaries: $75,000 Less Than $100,000"
    WAGE_8 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_8.sum())
    target_name = "Wages and Salaries: $100,000 Less Than $200,000"
    WAGE_9 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
              wage_9.sum())
    target_name = "Wages and Salaries: $200,000 Less Than $500,000"
    WAGE_10 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
               wage_10.sum())
    target_name = "Wages and Salaries: $500,000 Less Than $1 Million"
    WAGE_11 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
               wage_11.sum())
    target_name = "Wages and Salaries: $1 Million and Over"
    WAGE_12 = (Stage_II_targets[year][target_name] * APOPN / AWAGE * 1000 -
               wage_12.sum())

    temp = [
        INTEREST, DIVIDEND, BIZ_INCOME, BIZ_LOSS, CAP_GAIN, ANNUITY_PENSION,
        SCH_E_INCOME, SCH_E_LOSS, SS_INCOME, UNEMPLOYMENT_COMP, WAGE_1, WAGE_2,
        WAGE_3, WAGE_4, WAGE_5, WAGE_6, WAGE_7, WAGE_8, WAGE_9, WAGE_10,
        WAGE_11, WAGE_12
    ]
    for m in temp:
        b.append(m)

    targets = CyLPArray(b)
    print("Targets for year {} are:".format(year))
    print(targets)

    LP = CyLPModel()

    r = LP.addVariable("r", puf_length)
    s = LP.addVariable("s", puf_length)

    print("Adding constraints for year {} .....".format(year))
    LP.addConstraint(r >= 0, "positive r")
    LP.addConstraint(s >= 0, "positive s")
    LP.addConstraint(r + s <= tol, "abs upperbound")

    c = CyLPArray((np.ones(puf_length)))
    LP.objective = c * r + c * s

    LP.addConstraint(A1 * r + A2 * s == targets, "Aggregates")

    print("Setting up the LP model for year {} .....".format(year))
    model = CyClpSimplex(LP)

    print("Solving LP for year {} .....".format(year))
    model.initialSolve()

    print("DONE solving LP for year {}".format(year))
    z = np.empty([puf_length])
    z = (1.0 + model.primalVariableSolution["r"] -
         model.primalVariableSolution["s"]) * s006 * 100
    return z
Example #25
0
def BranchAndBoundCylp(T, CONSTRAINTS, VARIABLES, OBJ, MAT, RHS,
                   branch_strategy=MOST_FRACTIONAL,
                   search_strategy=DEPTH_FIRST,
                   complete_enumeration=False,
                   display_interval=None,
                   binary_vars=True):
    if T.get_layout() == 'dot2tex':
        cluster_attrs = {'name':'Key', 'label':r'\text{Key}', 'fontsize':'12'}
        T.add_node('C', label = r'\text{Candidate}', style = 'filled',
                      color = 'yellow', fillcolor = 'yellow')
        T.add_node('I', label = r'\text{Infeasible}', style = 'filled',
                      color = 'orange', fillcolor = 'orange')
        T.add_node('S', label = r'\text{Solution}', style = 'filled',
                      color = 'lightblue', fillcolor = 'lightblue')
        T.add_node('P', label = r'\text{Pruned}', style = 'filled',
                      color = 'red', fillcolor = 'red')
        T.add_node('PC', label = r'\text{Pruned}$\\ $\text{Candidate}', style = 'filled',
                      color = 'red', fillcolor = 'yellow')
    else:
        cluster_attrs = {'name':'Key', 'label':'Key', 'fontsize':'12'}
        T.add_node('C', label = 'Candidate', style = 'filled',
                      color = 'yellow', fillcolor = 'yellow')
        T.add_node('I', label = 'Infeasible', style = 'filled',
                      color = 'orange', fillcolor = 'orange')
        T.add_node('S', label = 'Solution', style = 'filled',
                      color = 'lightblue', fillcolor = 'lightblue')
        T.add_node('P', label = 'Pruned', style = 'filled',
                      color = 'red', fillcolor = 'red')
        T.add_node('PC', label = 'Pruned \n Candidate', style = 'filled',
                      color = 'red', fillcolor = 'yellow')
    T.add_edge('C', 'I', style = 'invisible', arrowhead = 'none')
    T.add_edge('I', 'S', style = 'invisible', arrowhead = 'none')
    T.add_edge('S', 'P', style = 'invisible', arrowhead = 'none')
    T.add_edge('P', 'PC', style = 'invisible', arrowhead = 'none')
    T.create_cluster(['C', 'I', 'S', 'P', 'PC'], cluster_attrs)

    # Change to CyLP format
    cyOBJ = CyLPArray([-val for val in OBJ.values()]) # CyLP takes min
    cyMAT = np.matrix([MAT[v] for v in VARIABLES]).T
    cyRHS = CyLPArray(RHS)


    # The initial lower bound
    LB = -INFINITY
    # The number of LP's solved, and the number of nodes solved
    node_count = 1
    iter_count = 0
    lp_count = 0

    numCons = len(CONSTRAINTS)
    numVars = len(VARIABLES)
    # List of incumbent solution variable values
    opt = dict([(i, 0) for i in VARIABLES])
    pseudo_u = dict((i, (OBJ[i], 0)) for i in VARIABLES)
    pseudo_d = dict((i, (OBJ[i], 0)) for i in VARIABLES)
    print("===========================================")
    print("Starting Branch and Bound")
    if branch_strategy == MOST_FRACTIONAL:
        print("Most fractional variable")
    elif branch_strategy == FIXED_BRANCHING:
        print("Fixed order")
    elif branch_strategy == PSEUDOCOST_BRANCHING:
        print("Pseudocost brancing")
    else:
        print("Unknown branching strategy %s" %branch_strategy)
    if search_strategy == DEPTH_FIRST:
        print("Depth first search strategy")
    elif search_strategy == BEST_FIRST:
        print("Best first search strategy")
    else:
        print("Unknown search strategy %s" %search_strategy)
    print("===========================================")
    # List of candidate nodes
    Q = PriorityQueue()
    # The current tree depth
    cur_depth = 0
    cur_index = 0
    # Timer
    timer = time.time()
    Q.push(0, -INFINITY, (0, None, None, None, None, None, None))
    # Branch and Bound Loop
    while not Q.isEmpty():
        infeasible = False
        integer_solution = False
        (cur_index, parent, relax, branch_var, branch_var_value, sense,
        rhs) = Q.pop()
        if cur_index is not 0:
            cur_depth = T.get_node_attr(parent, 'level') + 1
        else:
            cur_depth = 0
        print("")
        print("----------------------------------------------------")
        print("")
        if LB > -INFINITY:
            print("Node: %s, Depth: %s, LB: %s" %(cur_index,cur_depth,LB))
        else:
            print("Node: %s, Depth: %s, LB: %s" %(cur_index,cur_depth,"None"))
        if relax is not None and relax <= LB:
            print("Node pruned immediately by bound")
            T.set_node_attr(parent, 'color', 'red')
            continue
        #====================================
        #    LP Relaxation
        #====================================
        # Compute lower bound by LP relaxation
        prob = CyLPModel()

        # CyLP do not allow change variable object without model
        if binary_vars:
            var = prob.addVariable('x', dim=len(VARIABLES))
            prob += 0 <= var <= 1
        else:
            var = prob.addVariable('x', dim=len(VARIABLES))
            prob += 0 <= var # To avoid random generated problems be unbounded


        prob += cyMAT * var <= RHS
        prob.objective = cyOBJ * var
        s = CyClpSimplex(prob)

        # Fix all prescribed variables
        branch_vars = []
        if cur_index is not 0:
            sys.stdout.write("Branching variables: ")
            branch_vars.append(branch_var)
            if sense == '>=':
                prob += var[int(branch_var[1:])] >= rhs # slice the name for index
            else:
                prob += var[int(branch_var[1:])] <= rhs # slice the name for index
            print(branch_var, end=' ')
            pred = parent
            while not str(pred) == '0':
                pred_branch_var = T.get_node_attr(pred, 'branch_var')
                pred_rhs = T.get_node_attr(pred, 'rhs')
                pred_sense = T.get_node_attr(pred, 'sense')
                if pred_sense == '<=':
                    prob += var[int(pred_branch_var[1:])] <= pred_rhs
                else:
                    prob += var[int(pred_branch_var[1:])] >= pred_rhs
                print(pred_branch_var, end=' ')
                branch_vars.append(pred_branch_var)
                pred = T.get_node_attr(pred, 'parent')
            print()
        # Solve the LP relaxation
        s = CyClpSimplex(prob)
        s.initialSolve()
        lp_count = lp_count +1

        if (s.getStatusCode() < 0):
            print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
            print(lp_count)
            print(s.getStatusCode())
            print(s.primal())
            print(s.objectiveValue)
            print(s.primalVariableSolution)
            print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')

        # Check infeasibility
        #-1 - unknown e.g. before solve or if postSolve says not optimal
        #0 - optimal
        #1 - primal infeasible
        #2 - dual infeasible
        #3 - stopped on iterations or time
        #4 - stopped due to errors
        #5 - stopped by event handler (virtual int ClpEventHandler::event())
        infeasible = (s.getStatusCode() in [-1,1,3,4,5])
        # Print status
        if infeasible:
            print("LP Solved, status: Infeasible")
        else:
            print("LP Solved, status: %s, obj: %s" %(s.getStatusString(),-s.objectiveValue))

        if(s.getStatusCode() == 0):
            relax = -s.objectiveValue
            # Update pseudocost
            if branch_var != None:
                if sense == '<=':
                    pseudo_d[branch_var] = (
                    old_div((pseudo_d[branch_var][0]*pseudo_d[branch_var][1] +
                    old_div((T.get_node_attr(parent, 'obj') - relax),
                    (branch_var_value - rhs))),(pseudo_d[branch_var][1]+1)),
                    pseudo_d[branch_var][1]+1)
                else:
                    pseudo_u[branch_var] = (
                    old_div((pseudo_u[branch_var][0]*pseudo_d[branch_var][1] +
                     old_div((T.get_node_attr(parent, 'obj') - relax),
                     (rhs - branch_var_value))),(pseudo_u[branch_var][1]+1)),
                    pseudo_u[branch_var][1]+1)
            var_values = dict([(i, s.primalVariableSolution['x'][int(i[1:])]) for i in VARIABLES])
            integer_solution = 1
            for i in VARIABLES:
                if (abs(round(var_values[i]) - var_values[i]) > .001):
                    integer_solution = 0
                    break
            # Determine integer_infeasibility_count and
            # Integer_infeasibility_sum for scatterplot and such
            integer_infeasibility_count = 0
            integer_infeasibility_sum = 0.0
            for i in VARIABLES:
                if (var_values[i] not in set([0,1])):
                    integer_infeasibility_count += 1
                    integer_infeasibility_sum += min([var_values[i],
                                                      1.0-var_values[i]])
            if (integer_solution and relax>LB):
                LB = relax
                for i in VARIABLES:
                    # These two have different data structures first one
                    #list, second one dictionary
                    opt[i] = var_values[i]
                print("New best solution found, objective: %s" %relax)
                for i in VARIABLES:
                    if var_values[i] > 0:
                        print("%s = %s" %(i, var_values[i]))
            elif (integer_solution and relax<=LB):
                print("New integer solution found, objective: %s" %relax)
                for i in VARIABLES:
                    if var_values[i] > 0:
                        print("%s = %s" %(i, var_values[i]))
            else:
                print("Fractional solution:")
                for i in VARIABLES:
                    if var_values[i] > 0:
                        print("%s = %s" %(i, var_values[i]))
            #For complete enumeration
            if complete_enumeration:
                relax = LB - 1
        else:
            relax = INFINITY
        if integer_solution:
            print("Integer solution")
            BBstatus = 'S'
            status = 'integer'
            color = 'lightblue'
        elif infeasible:
            print("Infeasible node")
            BBstatus = 'I'
            status = 'infeasible'
            color = 'orange'
        elif not complete_enumeration and relax <= LB:
            print("Node pruned by bound (obj: %s, UB: %s)" %(relax,LB))
            BBstatus = 'P'
            status = 'fathomed'
            color = 'red'
        elif cur_depth >= numVars :
            print("Reached a leaf")
            BBstatus = 'fathomed'
            status = 'L'
        else:
            BBstatus = 'C'
            status = 'candidate'
            color = 'yellow'
        if BBstatus is 'I':
            if T.get_layout() == 'dot2tex':
                label = '\text{I}'
            else:
                label = 'I'
        else:
            label = "%.1f"%relax
        if iter_count == 0:
            if status is not 'candidate':
                integer_infeasibility_count = None
                integer_infeasibility_sum = None
            if status is 'fathomed':
                if T._incumbent_value is None:
                    print('WARNING: Encountered "fathom" line before '+\
                        'first incumbent.')
            T.AddOrUpdateNode(0, None, None, 'candidate', relax,
                             integer_infeasibility_count,
                             integer_infeasibility_sum,
                             label = label,
                             obj = relax, color = color,
                             style = 'filled', fillcolor = color)
            if status is 'integer':
                T._previous_incumbent_value = T._incumbent_value
                T._incumbent_value = relax
                T._incumbent_parent = -1
                T._new_integer_solution = True
    #           #Currently broken
    #           if ETREE_INSTALLED and T.attr['display'] == 'svg':
    #               T.write_as_svg(filename = "node%d" % iter_count,
    #                                 nextfile = "node%d" % (iter_count + 1),
    #                                 highlight = cur_index)
        else:
            _direction = {'<=':'L', '>=':'R'}
            if status is 'infeasible':
                integer_infeasibility_count = T.get_node_attr(parent,
                                     'integer_infeasibility_count')
                integer_infeasibility_sum = T.get_node_attr(parent,
                                     'integer_infeasibility_sum')
                relax = T.get_node_attr(parent, 'lp_bound')
            elif status is 'fathomed':
                if T._incumbent_value is None:
                    print('WARNING: Encountered "fathom" line before'+\
                        ' first incumbent.')
                    print('  This may indicate an error in the input file.')
            elif status is 'integer':
                integer_infeasibility_count = None
                integer_infeasibility_sum = None
            T.AddOrUpdateNode(cur_index, parent, _direction[sense],\
                                 status, relax,\
                                 integer_infeasibility_count,\
                                 integer_infeasibility_sum,\
                                 branch_var = branch_var,\
                                 branch_var_value = var_values[branch_var],\
                                 sense = sense, rhs = rhs, obj = relax,\
                                 color = color, style = 'filled',\
                                 label = label, fillcolor = color)
            if status is 'integer':
                T._previous_incumbent_value = T._incumbent_value
                T._incumbent_value = relax
                T._incumbent_parent = parent
                T._new_integer_solution = True
            # Currently Broken
    #           if ETREE_INSTALLED and T.attr['display'] == 'svg':
    #               T.write_as_svg(filename = "node%d" % iter_count,
    #                                 prevfile = "node%d" % (iter_count - 1),
    #                                 nextfile = "node%d" % (iter_count + 1),
    #                                 highlight = cur_index)
            if T.get_layout() == 'dot2tex':
                _dot2tex_label = {'>=':' \geq ', '<=':' \leq '}
                T.set_edge_attr(parent, cur_index, 'label',\
                                   str(branch_var) + _dot2tex_label[sense] +\
                                   str(rhs))
            else:
                T.set_edge_attr(parent, cur_index, 'label',\
                                   str(branch_var) + sense + str(rhs))
        iter_count += 1
        if BBstatus == 'C':
            # Branching:
            # Choose a variable for branching
            branching_var = None
            if branch_strategy == FIXED_BRANCHING:
                #fixed order
                for i in VARIABLES:
                    frac = min(s.primalVariableSolution['x'][int(i[1:])]-math.floor(s.primalVariableSolution['x'][int(i[1:])]),\
                               math.ceil(s.primalVariableSolution['x'][int(i[1:])]) - s.primalVariableSolution['x'][int(i[1:])])
                    if (frac > 0):
                        min_frac = frac
                        branching_var = i
                        # TODO(aykut): understand this break
                        break
            elif branch_strategy == MOST_FRACTIONAL:
                #most fractional variable
                min_frac = -1
                for i in VARIABLES:
                    frac = min(s.primalVariableSolution['x'][int(i[1:])]-math.floor(s.primalVariableSolution['x'][int(i[1:])]),\
                               math.ceil(s.primalVariableSolution['x'][int(i[1:])])- s.primalVariableSolution['x'][int(i[1:])])
                    if (frac> min_frac):
                        min_frac = frac
                        branching_var = i
            elif branch_strategy == PSEUDOCOST_BRANCHING:
                scores = {}
                for i in VARIABLES:
                    # find the fractional solutions
                    if (s.primalVariableSolution['x'][int(i[1:])] - math.floor(s.primalVariableSolution['x'][int(i[1:])])) != 0:
                        scores[i] = min(pseudo_u[i][0]*(1-s.primalVariableSolution['x'][int(i[1:])]),\
                                        pseudo_d[i][0]*s.primalVariableSolution['x'][int(i[1:])])
                    # sort the dictionary by value
                branching_var = sorted(list(scores.items()),
                                       key=lambda x : x[1])[-1][0]
            else:
                print("Unknown branching strategy %s" %branch_strategy)
                exit()
            if branching_var is not None:
                print("Branching on variable %s" %branching_var)
            #Create new nodes
            if search_strategy == DEPTH_FIRST:
                priority = (-cur_depth - 1, -cur_depth - 1)
            elif search_strategy == BEST_FIRST:
                priority = (-relax, -relax)
            elif search_strategy == BEST_ESTIMATE:
                priority = (-relax - pseudo_d[branching_var][0]*\
                                 (math.floor(s.primalVariableSolution['x'][int(branching_var[1:])]) -\
                                      s.primalVariableSolution['x'][int(branching_var[1:])]),\
                            -relax + pseudo_u[branching_var][0]*\
                                 (math.ceil(s.primalVariableSolution['x'][int(branching_var[1:])]) -\
                                      s.primalVariableSolution['x'][int(branching_var[1:])]))
            node_count += 1
            Q.push(node_count, priority[0], (node_count, cur_index, relax, branching_var,
                    var_values[branching_var],
                    '<=', math.floor(s.primalVariableSolution['x'][int(branching_var[1:])])))
            node_count += 1
            Q.push(node_count, priority[1], (node_count, cur_index, relax, branching_var,
                    var_values[branching_var],
                    '>=', math.ceil(s.primalVariableSolution['x'][int(branching_var[1:])])))
            T.set_node_attr(cur_index, color, 'green')
        if T.root is not None and display_interval is not None and\
                iter_count%display_interval == 0:
            T.display(count=iter_count)

    timer = int(math.ceil((time.time()-timer)*1000))
    print("")
    print("===========================================")
    print("Branch and bound completed in %sms" %timer)
    print("Strategy: %s" %branch_strategy)
    if complete_enumeration:
        print("Complete enumeration")
    print("%s nodes visited " %node_count)
    print("%s LP's solved" %lp_count)
    print("===========================================")
    print("Optimal solution")
    #print optimal solution
    for i in sorted(VARIABLES):
        if opt[i] > 0:
            print("%s = %s" %(i, opt[i]))
    print("Objective function value")
    print(LB)
    print("===========================================")
    if T.attr['display'] is not 'off':
        T.display(count=iter_count)
    T._lp_count = lp_count
    return LB,opt
Example #26
0
def LP_solver_cylp(A_Matrix, B_vectors, weights, really_verbose=False):
    """
    Solve the Linear Programming problem given in Giangrande et al, 2012 using
    the CyLP module.

    Parameters
    ----------
    A_Matrix : matrix
        Row augmented A matrix, see :py:func:`construct_A_matrix`
    B_vectors : matrix
        Matrix containing B vectors, see :py:func:`construct_B_vectors`
    weights : array
        Weights.
    really_verbose : bool
        True to print CLP messaging. False to suppress.

    Returns
    -------
    soln : array
        Solution to LP problem.

    See Also
    --------
    LP_solver_cvxopt : Solve LP problem using the CVXOPT module.
    LP_solver_pyglpk : Solve LP problem using the PyGLPK module.

    """
    from cylp.cy.CyClpSimplex import CyClpSimplex
    from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray

    n_gates = weights.shape[1] // 2
    n_rays = B_vectors.shape[0]
    soln = np.zeros([n_rays, n_gates])

    # Create CyLPModel and initialize it
    model = CyLPModel()
    G = np.matrix(A_Matrix)
    h = CyLPArray(np.empty(B_vectors.shape[1]))
    x = model.addVariable('x', G.shape[1])
    model.addConstraint(G * x >= h)
    #c = CyLPArray(np.empty(weights.shape[1]))
    c = CyLPArray(np.squeeze(weights[0]))
    model.objective = c * x

    # import model in solver
    s = CyClpSimplex(model)
    # disable logging
    if not really_verbose:
        s.logLevel = 0

    for raynum in range(n_rays):

        # set new B_vector values for actual ray
        s.setRowLowerArray(np.squeeze(np.asarray(B_vectors[raynum])))
        # set new weights (objectives) for actual ray
        #s.setObjectiveArray(np.squeeze(np.asarray(weights[raynum])))
        # solve with dual method, it is faster
        s.dual()
        # extract primal solution
        soln[raynum, :] = s.primalVariableSolution['x'][n_gates:2 * n_gates]

    # apply smoothing filter on a per scan basis
    soln = smooth_and_trim_scan(soln, window_len=5, window='sg_smooth')
    return soln
Example #27
0
    def solve_via_data(self, data, warm_start, verbose, solver_opts, solver_cache=None):
        # Import basic modelling tools of cylp
        from cylp.cy import CyClpSimplex
        from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray

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

        n = c.shape[0]

        # Problem
        model = CyLPModel()

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

        # Constraints
        # eq
        model += A[0:dims[s.EQ_DIM], :] * x == CyLPArray(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 <= CyLPArray(b[leq_start:leq_end])

        # Objective
        model.objective = c

        # Convert model
        model = CyClpSimplex(model)

        # No boolean vars available in Cbc -> model as int + restrict to [0,1]
        if data[s.BOOL_IDX] or data[s.INT_IDX]:
            # Mark integer- and binary-vars as "integer"
            model.setInteger(x[data[s.BOOL_IDX]])
            model.setInteger(x[data[s.INT_IDX]])

            # Restrict binary vars only
            idxs = data[s.BOOL_IDX]
            n_idxs = len(idxs)

            model.setColumnLowerSubset(np.arange(n_idxs, dtype=np.int32),
                                       np.array(idxs, np.int32),
                                       np.zeros(n_idxs))

            model.setColumnUpperSubset(np.arange(n_idxs, dtype=np.int32),
                                       np.array(idxs, np.int32),
                                       np.ones(n_idxs))

        # Verbosity Clp
        if not verbose:
            model.logLevel = 0

        # Build model & solve
        status = None
        if data[s.BOOL_IDX] or data[s.INT_IDX]:
            # Convert model
            cbcModel = model.getCbcModel()
            for key, value in solver_opts.items():
                setattr(cbcModel, key, value)

            # Verbosity Cbc
            if not verbose:
                cbcModel.logLevel = 0

            # cylp: /cylp/cy/CyCbcModel.pyx#L134
            # Call CbcMain. Solve the problem using the same parameters used by
            # CbcSolver. Equivalent to solving the model from the command line
            # using cbc's binary.
            cbcModel.solve()
            status = cbcModel.status
        else:
            # cylp: /cylp/cy/CyClpSimplex.pyx
            # Run CLP's initialSolve. It does a presolve and uses primal or dual
            # Simplex to solve a problem.
            status = model.initialSolve()

        solution = {}
        if data[s.BOOL_IDX] or data[s.INT_IDX]:
            solution["status"] = self.STATUS_MAP_MIP[status]
            solution["primal"] = cbcModel.primalVariableSolution['x']
            solution["value"] = cbcModel.objectiveValue
        else:
            solution["status"] = self.STATUS_MAP_LP[status]
            solution["primal"] = model.primalVariableSolution['x']
            solution["value"] = model.objectiveValue

        return solution
Example #28
0
def LP_solver_cylp(A_Matrix, B_vectors, weights, really_verbose=False):
    """
    Solve the Linear Programming problem given in Giangrande et al, 2012 using
    the CyLP module.

    Parameters
    ----------
    A_Matrix : matrix
        Row augmented A matrix, see :py:func:`construct_A_matrix`
    B_vectors : matrix
        Matrix containing B vectors, see :py:func:`construct_B_vectors`
    weights : array
        Weights.
    really_verbose : bool
        True to print CLP messaging. False to suppress.

    Returns
    -------
    soln : array
        Solution to LP problem.

    See Also
    --------
    LP_solver_cvxopt : Solve LP problem using the CVXOPT module.
    LP_solver_pyglpk : Solve LP problem using the PyGLPK module.

    """
    from cylp.cy.CyClpSimplex import CyClpSimplex
    from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray

    n_gates = weights.shape[1] // 2
    n_rays = B_vectors.shape[0]
    soln = np.zeros([n_rays, n_gates])

    # Create CyLPModel and initialize it
    model = CyLPModel()
    G = np.matrix(A_Matrix)
    h = CyLPArray(np.empty(B_vectors.shape[1]))
    x = model.addVariable('x', G.shape[1])
    model.addConstraint(G * x >= h)
    #c = CyLPArray(np.empty(weights.shape[1]))
    c = CyLPArray(np.squeeze(weights[0]))
    model.objective = c * x

    # import model in solver
    s = CyClpSimplex(model)
    # disable logging
    if not really_verbose:
            s.logLevel = 0

    for raynum in range(n_rays):

        # set new B_vector values for actual ray
        s.setRowLowerArray(np.squeeze(np.asarray(B_vectors[raynum])))
        # set new weights (objectives) for actual ray
        #s.setObjectiveArray(np.squeeze(np.asarray(weights[raynum])))
        # solve with dual method, it is faster
        s.dual()
        # extract primal solution
        soln[raynum, :] = s.primalVariableSolution['x'][n_gates: 2 * n_gates]

    # apply smoothing filter on a per scan basis
    soln = smooth_and_trim_scan(soln, window_len=5, window='sg_smooth')
    return soln
    def test_multiVar(self):
        model = CyLPModel()

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

        A = np.matrix([[1., 2., 0], [1., 0, 1.]])
        B = np.matrix([[1., 0, 0], [0, 0, 1.]])
        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())

        s += x[2] + y[1] >= 2.1
        s.primal()
        sol = np.concatenate(
            (s.primalVariableSolution['x'], s.primalVariableSolution['y']))
        self.assertTrue(
            (abs(sol - np.array([0, 2, 1.1, 0, 1])) <= 10**-6).all())
Example #30
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 CyLPModel, 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]
        data[s.BOOL_IDX] = solver_opts[s.BOOL_IDX]
        data[s.INT_IDX] = solver_opts[s.INT_IDX]

        n = c.shape[0]

        # Problem
        model = CyLPModel()

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

        # Constraints
        # eq
        model += A[0:dims[s.EQ_DIM], :] * x == CyLPArray(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 <= CyLPArray(b[leq_start:leq_end])

        # Objective
        model.objective = c

        # Convert model
        model = CyClpSimplex(model)

        # No boolean vars available in Cbc -> model as int + restrict to [0,1]
        if self.is_mip(data):
            # Mark integer- and binary-vars as "integer"
            model.setInteger(x[data[s.BOOL_IDX]])
            model.setInteger(x[data[s.INT_IDX]])

            # Restrict binary vars only
            idxs = data[s.BOOL_IDX]
            n_idxs = len(idxs)

            model.setColumnLowerSubset(np.arange(n_idxs, dtype=np.int32),
                                       np.array(idxs, np.int32),
                                       np.zeros(n_idxs))

            model.setColumnUpperSubset(np.arange(n_idxs, dtype=np.int32),
                                       np.array(idxs, np.int32),
                                       np.ones(n_idxs))

        # Verbosity Clp
        if not verbose:
            model.logLevel = 0

        # Build model & solve
        status = None
        if self.is_mip(data):
            # Convert model
            cbcModel = model.getCbcModel()

            # Verbosity Cbc
            if not verbose:
                cbcModel.logLevel = 0

            # cylp: /cylp/cy/CyCbcModel.pyx#L134
            # Call CbcMain. Solve the problem using the same parameters used by
            # CbcSolver. Equivalent to solving the model from the command line
            # using cbc's binary.
            cbcModel.solve()
            status = cbcModel.status
        else:
            # cylp: /cylp/cy/CyClpSimplex.pyx
            # Run CLP's initialSolve. It does a presolve and uses primal or dual
            # Simplex to solve a problem.
            status = model.initialSolve()

        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)
def get_model_quality_estimate_clp(settings, n, k, node_pos, node_val,
                                   num_iterations):
    """Compute an estimate of model quality using LPs with Clp.

    Computes an estimate of model quality, performing
    cross-validation. This version does not use all interpolation
    nodes, but rather only the best num_iterations ones, and it uses a
    sequence of LPs instead of a brute-force calculation. It should be
    much faster than the brute-force calculation, as each LP in the
    sequence requires only two pivots. The solver is COIN-OR Clp.

    Parameters
    ----------
    settings : rbfopt_settings.RbfSettings
        Global and algorithmic settings.

    n : int
        Dimension of the problem, i.e. the space where the point lives.

    k : int
        Number of nodes, i.e. interpolation points.

    node_pos : List[List[float]]
        Location of current interpolation nodes.

    node_val : List[float]
        List of values of the function at the nodes.

    num_iterations : int
        Number of nodes on which quality should be tested.
    
    Returns
    -------
    float
        An estimate of the leave-one-out cross-validation error, which
        can be interpreted as a measure of model quality.

    Raises
    ------
    RuntimeError
        If the LPs cannot be solved.

    ValueError
        If some settings are not supported.
    """
    assert(isinstance(settings, RbfSettings))
    assert(len(node_val)==k)
    assert(len(node_pos)==k)
    assert(num_iterations <= k)
    assert(cpx_available)
    # We cannot find a leave-one-out interpolant if the following
    # condition is not met.
    assert(k > n + 1)

    # Get size of polynomial part of the matrix (p) and sign of obj
    # function (sign)
    if (ru.get_degree_polynomial(settings) == 1):
        p = n + 1
        sign = 1
    elif (ru.get_degree_polynomial(settings) == 0):
        p = 1
        sign = -1
    else:
        raise ValueError('RBF type ' + settings.rbf + ' not supported')

    # Sort interpolation nodes by increasing objective function value
    sorted_list = sorted([(node_val[i], node_pos[i]) for i in range(k)])

    # Initialize the arrays used for the cross-validation
    cv_node_pos = [sorted_list[i][1] for i in range(k)]
    cv_node_val = [sorted_list[i][0] for i in range(k)]

    # Compute the RBF matrix, and the two submatrices of interest
    Amat = ru.get_rbf_matrix(settings, n, k, cv_node_pos)
    Phimat = Amat[:k, :k]
    Pmat = Amat[:k, k:]
    identity = np.matrix(np.identity(k))

    # Instantiate model
    model = CyLPModel()

    # Add variables: lambda, h, slacks
    rbf_lambda = model.addVariable('rbf_lambda', k)
    rbf_h = model.addVariable('rbf_h', p)
    slack = model.addVariable('slack', k)

    # Add constraints: interpolation conditions, unisolvence
    F = CyLPArray(cv_node_val)
    zeros = CyLPArray([0] * p)
    ones = CyLPArray([1] * p)
    if (p > 1):
        # We can use matrix form
        model += (Phimat * rbf_lambda + Pmat * rbf_h + identity * slack == F)
        model += (Pmat.transpose() * rbf_lambda == zeros)
    else:
        # Workaround for one dimensional variables: one row at a time
        for i in range(k):
            model += Phimat[i, :] * rbf_lambda + rbf_h + slack[i] == F[i]
        model += (Pmat.transpose() * rbf_lambda == zeros)

    # Add objective
    obj = CyLPArray([sign*val for val in node_val])
    model.objective = obj * rbf_lambda
                           
    # Create LP, suppress output, and set bounds
    lp = clp.CyClpSimplex(model)
    lp.logLevel = 0
    infinity = lp.getCoinInfinity()
    for i in range(k + p):
        lp.setColumnLower(i, -infinity)
        lp.setColumnUpper(i, infinity)
    for i in range(k):
        lp.setColumnLower(k + p + i, 0.0)
        lp.setColumnUpper(k + p + i, 0.0)

    # Estimate of the model error
    loo_error = 0.0

    for i in range(num_iterations):
        # Fix lambda[i] to zero
        lp.setColumnLower(i, 0.0)
        lp.setColumnUpper(i, 0.0)
        # Set slack[i] to unconstrained
        lp.setColumnLower(k + p + i, -infinity)
        lp.setColumnUpper(k + p + i, infinity)

        lp.dual(startFinishOptions = 'sx')

        if (not lp.getStatusCode() == 0):
            raise RuntimeError('Could not solve LP with Clp, status ' +
                               lp.getStatusString())

        lambda_sol = lp.primalVariableSolution['rbf_lambda'].tolist()
        h_sol = lp.primalVariableSolution['rbf_h'].tolist()

        # Compute value of the interpolant at the removed node
        predicted_val = ru.evaluate_rbf(settings, cv_node_pos[i], n, k,
                                        cv_node_pos, lambda_sol, h_sol)

        # Update leave-one-out error
        loo_error += abs(predicted_val - cv_node_val[i])

        # Fix lambda[i] to zero
        lp.setColumnLower(i, -infinity)
        lp.setColumnUpper(i, infinity)
        # Set slack[i] to unconstrained
        lp.setColumnLower(k + p + i, 0.0)
        lp.setColumnUpper(k + p + i, 0.0)

    return loo_error/num_iterations