PySCIPOpt icon indicating copy to clipboard operation
PySCIPOpt copied to clipboard

How to change objective Coefficients during pricing process

Open xhmywf opened this issue 4 years ago • 3 comments

Hello,in my branch and price process ,I want to change some objective Coefficients in the pricerredcost function.How to do it?

xhmywf avatar Nov 04 '21 06:11 xhmywf

Hi, thanks for your question, please have a look at the tests/test_pricer.py example and there is a setObjective function you can look into in the scip.pyx file.

Otherwise please provide a minimal example of your code and what you have tried to achieve the functionality you are looking for and maybe we can work this out.

CGraczyk avatar Nov 12 '21 16:11 CGraczyk

Thank you for your reply .It's a surprise to receive your reply so soon.When I use branch and price framework in SCIP ,it can't convergence quickly . So I want to realize stablized column generation(Stabilized column generation https://www.sciencedirect.com/science/article/pii/S0012365X98002131) to speed up .In this method ,everytime I add column in pricerredcost(), objective Coefficients should be changed.But when I try to change objective Coefficients like the example test_reopt do ,the SCIP : method cannot be called at this time in solution process! Later I will provide a minimal example.Keep in touch,I really need your help.

xhmywf avatar Nov 16 '21 09:11 xhmywf

from pyscipopt import Model, Pricer, SCIP_RESULT, SCIP_PARAMSETTING, quicksum

class CutPricer(Pricer):

# The reduced cost function for the variable pricer
def pricerredcost(self):

    # Retrieving the dual solutions
    dualSolutions = []
    for i, c in enumerate(self.data['cons']):
        dualSolutions.append(self.model.getDualsolLinear(c))

    # Building a MIP to solve the subproblem
    subMIP = Model("CuttingStock-Sub")

    # Turning off presolve
    subMIP.setPresolve(SCIP_PARAMSETTING.OFF)

    # Setting the verbosity level to 0
    subMIP.hideOutput()

    cutWidthVars = []
    varNames = []
    varBaseName = "CutWidth"

    # Variables for the subMIP
    for i in range(len(dualSolutions)):
        varNames.append(varBaseName + "_" + str(i))
        cutWidthVars.append(subMIP.addVar(varNames[i], vtype = "I", obj = -1.0 * dualSolutions[i]))

    # Adding the knapsack constraint
    knapsackCons = subMIP.addCons(
        quicksum(w*v for (w,v) in zip(self.data['widths'], cutWidthVars)) <= self.data['rollLength'])

    # Solving the subMIP to generate the most negative reduced cost pattern
    subMIP.optimize()

    objval = 1 + subMIP.getObjVal()


    #self.model
    self.model.freeReoptSolve()
    self.model.chgReoptObjective(4*self.data['var'][1]+3*self.data['var'][2])
    # Adding the column to the master problem
    if objval < -1e-08:
        currentNumVar = len(self.data['var'])

        # Creating new var; must set pricedVar to True
        newVar = self.model.addVar("NewPattern_" + str(currentNumVar), vtype = "I", obj = 1.0, pricedVar = True)

        # Adding the new variable to the constraints of the master problem
        newPattern = []
        for i, c in enumerate(self.data['cons']):
            coeff = round(subMIP.getVal(cutWidthVars[i]))
            if(coeff!=0):
                 self.model.addConsCoeff(c, newVar, coeff)

            newPattern.append(coeff)

        # Storing the new variable in the pricer data.
        self.data['patterns'].append(newPattern)
        self.data['var'].append(newVar)


    return {'result':SCIP_RESULT.SUCCESS}

# The initialisation function for the variable pricer to retrieve the transformed constraints of the problem
def pricerinit(self):
    for i, c in enumerate(self.data['cons']):
        self.data['cons'][i] = self.model.getTransformedCons(c)

def test_cuttingstock(): # create solver instance s = Model("CuttingStock")

s.setPresolve(0)
s.enableReoptimization()

# creating a pricer
pricer = CutPricer()
s.includePricer(pricer, "CuttingStockPricer", "Pricer to identify new cutting stock patterns")

# item widths
widths = [14, 31, 36, 45]
# width demand
demand = [211, 395, 610, 97]
# roll length
rollLength = 100
assert len(widths) == len(demand)

# adding the initial variables
cutPatternVars = []
varNames = []
varBaseName = "Pattern"
patterns = []

initialCoeffs = []
for i in range(len(widths)):
    varNames.append(varBaseName + "_" + str(i))
    cutPatternVars.append(s.addVar(varNames[i], vtype = "I",obj = 1.0))

# adding a linear constraint for the knapsack constraint
demandCons = []
for i in range(len(widths)):
    numWidthsPerRoll = float(int(rollLength/widths[i]))
    demandCons.append(s.addCons(numWidthsPerRoll*cutPatternVars[i] >= demand[i],
                                separate = False, modifiable = True))
    newPattern = [0]*len(widths)
    newPattern[i] = numWidthsPerRoll
    patterns.append(newPattern)

# Setting the pricer_data for use in the init and redcost functions
pricer.data = {}
pricer.data['var'] = cutPatternVars
pricer.data['cons'] = demandCons
pricer.data['widths'] = widths
pricer.data['demand'] = demand
pricer.data['rollLength'] = rollLength
pricer.data['patterns'] = patterns

# solve problem
s.optimize()

# print original data
printWidths = '\t'.join(str(e) for e in widths)
print('\nInput Data')
print('==========')
print('Roll Length:', rollLength)
print('Widths:\t', printWidths)
print('Demand:\t', '\t'.join(str(e) for e in demand))

# print solution
widthOutput = [0]*len(widths)
print('\nResult')
print('======')
print('\t\tSol Value', '\tWidths\t', printWidths)
for i in range(len(pricer.data['var'])):
    rollUsage = 0
    print(s.getVal(pricer.data['var'][i]))
    solValue = round(s.getVal(pricer.data['var'][i]))
    if solValue > 0:
        outline = 'Pattern_' + str(i) + ':\t' + str(solValue) + '\t\tCuts:\t '
        for j in range(len(widths)):
            rollUsage += pricer.data['patterns'][i][j]*widths[j]
            widthOutput[j] += pricer.data['patterns'][i][j]*solValue
            outline += str(pricer.data['patterns'][i][j]) + '\t'
        outline += 'Usage:' + str(rollUsage)
        print(outline)

print('\t\t\tTotal Output:\t', '\t'.join(str(e) for e in widthOutput))

assert s.getObjVal() == 452.25

if name == 'main': test_cuttingstock()

A minimal example is provided above.When I run this program,it finieshed with error: Process finished with exit code -1073741819 (0xC0000005) Hope for your reply soon.

xhmywf avatar Nov 17 '21 04:11 xhmywf

This is a bit late, but short answer: SCIP does not allow objective coefficients to change. You would need to remove the column and add a new one as a workaround.

ambros-gleixner avatar Aug 25 '22 04:08 ambros-gleixner