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())
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())
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())
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]])
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())
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
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())
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())
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
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
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
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
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
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
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
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 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
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())
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