//===========================================================================// void ATM_DecompApp::createModels(){ //--- //--- This function does the work to create the different models //--- that will be used. This memory is owned by the user. It will //--- be passed to the application interface and used by the algorithms. //--- UtilPrintFuncBegin(m_osLog, m_classTag, "APPcreateModel()", m_appParam.LogLevel, 2); //--- //--- The original problem is in the form of a MINLP: //--- min sum{a in A, d in D} | f[a,d] | //--- s.t. //--- for a in A, d in D: //--- f[a,d] = //--- a[a,d] x1[a] + //--- b[a,d] x2[a] + //--- c[a,d] x1[a] x2[a] + //--- d[a,d] x3[a] + //--- e[a,d] //--- for d in D: //--- sum{a in A} f[a,d] <= B[d] //--- for a in A: //--- |{d in D : f[a,d] < 0} | <= K[a] (notice strict ineq) //--- for a in A, d in D: //--- f[a,d] free //--- for a in A: //--- x1[a], x2[a] in [0,1], x3[a] >= 0 //--- //--- //--- Discretization of continuous variable. //--- n = number of steps //--- T = {1, ..., n} //--- sum{t in T} (t/n) * x1[a,t] = x1[a], for a in A //--- sum{t in T} x1[a,t] <= 1 , for a in A //--- so, if n=10, x1[a] in {0,0.1,0.2,...,1.0}. //--- //--- //--- Linearization of product of a binary and a continuous. //--- For a in A, t in T: //--- z[a,t] = x1[a,t] * x2[a] //--- <==> //--- z[a,t] >= 0 <= 1, //--- z[a,t] <= x1[a,t], //--- z[a,t] <= x2[a], //--- z[a,t] >= x1[a,t] + x2[a] - 1. //--- //--- //--- Linearization of the absolute value. //--- For a in A, d in D: //--- f+[a,d], f-[a,d] >= 0 //--- f[a,d] = f+[a,d] - f-[a,d] //--- |f[a,d]|= f+[a,d] + f-[a,d] //--- //--- //--- To model the count constraints. //--- For a in A: //--- |{d in D : f[a,d] < 0}| <= K[a] //--- <==> //--- |{d in D : f+[a,d] - f-[a,d] < 0}| <= K[a] //--- //--- At optimality, if f[a,d] != 0, then either //--- f+[a,d] > 0 and f-[a,d] = 0, or //--- f+[a,d] = 0 and f-[a,d] > 0. //--- So, to count the cases when f[a,d] < 0, we can restrict //--- attention to the cases where f-[a,d] > 0. //--- //--- With some application specific stuff, //--- we know that f-[a,d] <= w[a,d]. //--- //--- So, to count the number of cases we can use the following: //--- f-[a,d] > 0 ==> v[a,d] = 1 //--- f-[a,d] <= 0 <== v[a,d] = 0 //--- <==> //--- f-[a,d] <= w[a,d] * v[a,d] //--- //--- and, then //--- |{d in D : f+[a,d] - f-[a,d] < 0}| <= K[a] //--- <==> //--- sum{d in D} v[a,d] <= K[a] //--- //--- //--- (Approximate) MILP Reformulation //--- //--- min sum{a in A, d in D} f+[a,d] + f-[a,d] //--- s.t. //--- for a in A, d in D: //--- f+[a,d] - f-[a,d] = //--- a[a,d] sum{t in T} (t/n) x1[a,t] + //--- b[a,d] x2[a] + //--- c[a,d] sum{t in T} (t/n) z[a,t] + //--- d[a,d] x3[a] + //--- e[a,d] //--- f-[a,d] <= w[a,d] * v[a,d] //--- for a in A: //--- sum{t in T} x1[a,t] <= 1 //--- for a in A, t in T: //--- z[a,t] <= x1[a,t], //--- z[a,t] <= x2[a], //--- z[a,t] >= x1[a,t] + x2[a] - 1. //--- for d in D: //--- sum{a in A} (f+[a,d] - f-[a,d]) <= B[d] //--- for a in A: //--- sum{d in D} v[a,d] <= K[a] //--- for a in A, d in D: //--- f+[a,d], f-[a,d] >= 0 //--- f-[a,d] <= w[a,d] //--- v[a,d] in {0,1} //--- for a in A: //--- x2[a], x3[a] in [0,1] //--- for a in A, t in T //--- x1[a,t] in {0,1}, z[a,t] in [0,1] //--- //--- //--- UPDATE (April 2010). //--- //--- A tighter formulation of the //--- linearization of product of a binary and a continuous //--- is possible due to the constraint: sum{t in T} x1[a,t] <= 1 //--- //--- For a in A, t in T: //--- z[a,t] = x1[a,t] * x2[a] //--- <==> //--- OLD: //--- for a in A: //--- sum{t in T} x1[a,t] <= 1 (where, T = 1..n) //--- for a in A, t in T: //--- z[a,t] >= 0 <= 1, //--- z[a,t] <= x1[a,t], //--- z[a,t] <= x2[a], //--- z[a,t] >= x1[a,t] + x2[a] - 1. //--- NEW: //--- for a in A: //--- sum{t in T} x1[a,t] = 1 (where, T = 0..n) //--- sum{t in T} z[a,t] = x2[a] //--- for a in A, t in T: //--- z[a,t] >= 0 <= 1, //--- z[a,t] <= x1[a,t]. //--- //--- //--- Columns //--- x1[a,t] (binary) //--- z [a,t] //--- f+[a,d] //--- f-[a,d] //--- x2[a] //--- x3[a] //---- v[a,d] (binary) //--- int i, a; int nAtms = m_instance.getNAtms(); int numCols = numCoreCols(); //--- //--- Construct the objective function. //--- Coefficients of f+ and f- are 1.0, the rest are 0. //--- m_objective = new double[numCols]; if(!m_objective) throw UtilExceptionMemory("createModels", "MMKP_DecompApp"); UtilFillN(m_objective, numCols, 0.0); for(i = getColOffset_fp(); i < getColOffset_x2(); i++) m_objective[i] = 1.0; setModelObjective(m_objective, numCols); //--- //--- A'' (core): //--- for d in D: //--- sum{a in A} (f+[a,d] - f-[a,d]) <= B[d] //--- for a in A: <--- option ( core or relax ) //--- sum{d in D} v[a,d] <= K[a] //--- //--- A'[a] for a in A (independent blocks) //--- for d in D: //--- f+[a,d] - f-[a,d] = //--- a[a,d] sum{t in T} (t/n) x1[a,t] + //--- b[a,d] x2[a] + //--- c[a,d] sum{t in T} (t/n) z[a,t] + //--- d[a,d] x3[a] + //--- e[a,d] //--- f-[a,d] <= w[a,d] * v[a,d] //--- sum{t in T} x1[a,t] <= 1 //--- for t in T: //--- z[a,t] <= x1[a,t], //--- z[a,t] <= x2[a], //--- z[a,t] >= x1[a,t] + x2[a] - 1. //--- sum{d in D} v[a,d] <= K[a] <--- option ( core or relax ) //--- if(m_appParam.ModelNameCore == "BUDGET"){ DecompConstraintSet * modelCore = createModelCore1(false); m_models.push_back(modelCore); setModelCore(modelCore, "BUDGET"); } if(m_appParam.ModelNameCore == "BUDGET_COUNT"){ DecompConstraintSet * modelCore = createModelCore1(); m_models.push_back(modelCore); setModelCore(modelCore, "BUDGET_COUNT"); } if(m_appParam.ModelNameRelax == "CASH"){ for(a = 0; a < nAtms; a++){ DecompConstraintSet * modelRelax = createModelRelax1(a, false); m_models.push_back(modelRelax); setModelRelax(modelRelax, "CASH" + UtilIntToStr(a), a); } } if(m_appParam.ModelNameRelax == "CASH_COUNT"){ for(a = 0; a < nAtms; a++){ DecompConstraintSet * modelRelax = createModelRelax1(a); m_models.push_back(modelRelax); setModelRelax(modelRelax, "CASH_COUNT" + UtilIntToStr(a), a); } } if(m_appParam.ModelNameRelaxNest == "CASH_COUNT"){ for(a = 0; a < nAtms; a++){ DecompConstraintSet * modelRelax = createModelRelax1(a); m_models.push_back(modelRelax); setModelRelaxNest(modelRelax, "CASH_COUNT" + UtilIntToStr(a), a); } } //TODO: solve this A' with gap as relaxNest - but // we are doing blocks - so find a column then break it out // tell framework to do that? or do as user? show how we can // get stuff back from framework to setup and solve... /*{ //--- //--- Version MODEL_MASTER_COUNT //--- is relaxation too hard? //--- //--- A'' (core): //--- for a in A: //--- sum{d in D} v[a,d] <= K[a] //--- //--- A' (relax): //--- for d in D: //--- sum{a in A} (f+[a,d] - f-[a,d]) <= B[d] //--- for a in A: //--- sum{t in T} x1[a,t] <= 1 //--- for a in A, t in T: //--- z[a,t] <= x1[a,t], //--- z[a,t] <= x2[a], //--- z[a,t] >= x1[a,t] + x2[a] - 1. //--- for a in A, d in D: //--- f+[a,d] - f-[a,d] = //--- a[a,d] sum{t in T} (t/n) x1[a,t] + //--- b[a,d] x2[a] + //--- c[a,d] sum{t in T} (t/n) z[a,t] + //--- d[a,d] x3[a] + //--- e[a,d] //--- f-[a,d] <= w[a,d] * v[a,d] //--- vector< DecompConstraintSet* > modelRelaxV; DecompConstraintSet * modelCoreCount = createModelCoreCount(); DecompConstraintSet * modelRelaxCount = createModelRelaxCount(); modelRelaxV.push_back(modelRelaxCount); modelCore.insert (make_pair(MODEL_COUNT, modelCoreCount)); modelRelax.insert(make_pair(MODEL_COUNT, modelRelaxV)); }*/ UtilPrintFuncEnd(m_osLog, m_classTag, "APPcreateModel()", m_appParam.LogLevel, 2); }
// --------------------------------------------------------------------- // int GAP_DecompApp::createModels() { //--- //--- This function does the work to create the different models //--- that will be used. This memory is owned by the user. It will //--- be passed to the application interface and used by the algorithms. //--- UtilPrintFuncBegin(m_osLog, m_classTag, "createModels()", m_appParam.LogLevel, 2); //--- //--- Generalized Assignment Problem (GAP) //--- m is number of machines (index i) //--- n is number of tasks (index j) //--- //--- min sum{i in 1..m, j in 1..n} p[i,j] x[i,j] //--- s.t. sum{ j in 1..n} w[i,j] x[i,j] <= b[i], i in 1..m //--- sum{i in 1..m } x[i,j] = 1 , j in 1..n //--- x[i,j] in {0,1}, i in 1..m, j in 1..n //--- //--- Example structure: m=3, n=4 //--- xxxx <= b[i=1] //--- xxxx <= b[i=2] //--- xxxx <= b[i=3] //--- x x x = 1 [j=1] //--- x x x = 1 [j=2] //--- x x x = 1 [j=3] //--- x x x = 1 [j=4] //--- //--- //--- Get information about this problem instance. //-- int i; string modelName; int status = GAPStatusOk; int nTasks = m_instance.getNTasks(); //n int nMachines = m_instance.getNMachines(); //m const int* profit = m_instance.getProfit(); int nCols = nTasks * nMachines; //--- //--- Construct the objective function (the original problem is //--- a maximization, so we flip the sign to make it minimization). //--- m_objective = new double[nCols]; assert(m_objective); if (!m_objective) { return GAPStatusOutOfMemory; } for (i = 0; i < nCols; i++) { m_objective[i] = profit[i]; } //--- //--- A'[i] for i=1..m: m independent knapsacks //--- sum{j in 1..n} w[i,j] x[i,j] <= b[i] //--- x[i,j] in {0,1}, i in 1..m, j in 1..n //--- //--- A'': //--- sum{i in 1..m} x[i,j] = 1, j in 1..n //--- //--- Example structure: m=3, n=4 //--- A'[i=1]: //--- xxxx <= b[i=1] //--- A'[i=2]: //--- xxxx <= b[i=2] //--- A'[i=3]: //--- xxxx <= b[i=3] //--- //--- A'': //--- x x x = 1 [j=1] //--- x x x = 1 [j=2] //--- x x x = 1 [j=3] //--- x x x = 1 [j=4] //--- setModelObjective(m_objective, nCols); DecompConstraintSet* modelCore = new DecompConstraintSet(); status = createModelPartAP(modelCore); if (status) { return status; } setModelCore(modelCore, "AP"); m_models.push_back(modelCore); for (i = 0; i < nMachines; i++) { DecompConstraintSet* modelRelax = new DecompConstraintSet(); status = createModelPartKP(modelRelax, i); modelName = "KP" + UtilIntToStr(i); setModelRelax(modelRelax, modelName, i); m_models.push_back(modelRelax); } UtilPrintFuncEnd(m_osLog, m_classTag, "createModels()", m_appParam.LogLevel, 2); return status; }
//===========================================================================// void OSDipApp::createModels() { UtilPrintFuncBegin(m_osLog, m_classTag, "createModels()", m_appParam.LogLevel, 2); int i; int j; const int nCols = m_osInterface.getVariableNumber(); const int nRows = m_osInterface.getConstraintNumber(); try{ //First the define the objective function over the entire variable space //Create the memory for the objective function m_objective = new double[nCols]; for (i = 0; i < nCols; i++) { m_objective[i] = m_osInterface.getObjectiveFunctionCoeff()[i]; //std::cout << "obj coeff = " << m_objective[i] << std::endl; } setModelObjective( m_objective); //--- //--- Construct the core matrix. //--- int nRowsRelax, nRowsCore; nRowsRelax = 0; nRowsCore = 0; std::vector<OtherConstraintOption*> otherConstraintOptions; std::vector<OtherConstraintOption*>::iterator vit; // // Now construct the block matrices // int *rowsRelax; int whichBlock; DecompConstraintSet *modelRelax = NULL; std::set<int> blockVars; //variables indexes in the specific block std::set<int> blockVarsAll; //all variable indexes that appear in a block std::set<int> blockConAll; //all constraint indexes that appear in a block std::set<int>::iterator sit; CoinPackedVector *row; int *rowVars; int rowSize; if (m_osInterface.m_osoption != NULL && m_osInterface.m_osoption->getNumberOfOtherConstraintOptions() > 0) { otherConstraintOptions = m_osInterface.m_osoption->getOtherConstraintOptions("Dip"); //iterate over the vector of contraint options for (vit = otherConstraintOptions.begin(); vit != otherConstraintOptions.end(); vit++) { // see if we have a Core Constraint Set if( ( (*vit)->name.compare("constraintSet") == 0) && ( (*vit)->type.compare("Block") == 0)) { //get the block number //ch = new char[(*vit)->value.size() + 1]; //ch[(*vit)->value.size()] = 0; //memcpy(ch, (*vit)->value.c_str(), (*vit)->value.size()); //whichBlock = atoi(ch); //delete ch; whichBlock = atoi( (*vit)->value.c_str() ); // first get the number of constraints in this block nRowsRelax = (*vit)->numberOfCon; rowsRelax = new int[nRowsRelax]; //now get the variable indexes for just this block //first clear indexes from a previous block blockVars.clear(); for (i = 0; i < nRowsRelax; i++) { rowsRelax[i] = (*vit)->con[i]->idx; if( (*vit)->con[i]->idx >= nRows) throw ErrorClass( "found an invalid row index in OSoL file"); m_blocks[ whichBlock].push_back( rowsRelax[i] ); //also add to the set of all rows if (blockConAll.find( (*vit)->con[i]->idx ) == blockConAll.end()) { blockConAll.insert( (*vit)->con[i]->idx ); } //add the variables for this row to the set blockVars row = m_osInterface.getRow(rowsRelax[i]); rowSize = row->getNumElements(); rowVars = row->getIndices(); for (j = 0; j < rowSize; j++) { if (blockVars.find(rowVars[j]) == blockVars.end()) { blockVars.insert(rowVars[j]); } } delete row; }//end for or rows in this block modelRelax = new DecompConstraintSet(); CoinAssertHint(modelRelax, "Error: Out of Memory"); //create the active columns in this block for (sit = blockVars.begin(); sit != blockVars.end(); sit++) { modelRelax->activeColumns.push_back( *sit); //insert into the all variables set also, but throw an execption //if already there -- same variable cannot be in more than one block if (blockVarsAll.find( *sit) == blockVarsAll.end()) { blockVarsAll.insert (*sit); }else{ throw ErrorClass("Variable " + UtilIntToStr(*sit) + " appears in more than one block"); } } // // if (m_appParam.LogLevel >= 3) { (*m_osLog) << "Active Columns : " << whichBlock << endl; UtilPrintVector(modelRelax->activeColumns, m_osLog); } createModelPartSparse(modelRelax, nRowsRelax, rowsRelax); //does not work for cutting planes //createModelPart(modelRelax, nRowsRelax, rowsRelax); //modelRelax->fixNonActiveColumns(); m_modelR.insert(make_pair(whichBlock + 1, modelRelax)); setModelRelax(modelRelax, "relax" + UtilIntToStr(whichBlock), whichBlock); if (m_appParam.LogLevel >= 3) { (*m_osLog) << std::endl << std::endl; (*m_osLog) << "HERE COMES THE DUPLICATION (WHEN createModelPartSparse USED)" << std::endl; } UtilPrintVector( modelRelax->activeColumns, m_osLog); //free local memory UTIL_DELARR( rowsRelax); } }//end for over constraint options }// if on ospton null //get the core constraints -- constraints NOT in a block int *rowsCore = NULL; int kount = 0; nRowsCore = nRows - blockConAll.size(); if(nRowsCore <= 0) throw ErrorClass("We need at least one coupling constraint"); rowsCore = new int[nRowsCore]; for(i = 0; i < nRows; i++){ if (blockConAll.find( i ) == blockConAll.end() ){ rowsCore[ kount++] = i; } } if( kount != nRowsCore) throw ErrorClass("There was an error counting coupling constraints"); DecompConstraintSet * modelCore = new DecompConstraintSet(); createModelPart(modelCore, nRowsCore, rowsCore); setModelCore(modelCore, "core"); //--- //--- save a pointer so we can delete it later //--- m_modelC = modelCore; //get the master only variables //modelCore->masterOnlyCols.push_back(i); for (i = 0; i < nCols; i++) { if (blockVarsAll.find(i) == blockVarsAll.end()) { modelCore->masterOnlyCols.push_back(i); std::cout << "MASTER ONLY VARIABLE " << i << std::endl; } } //--- //--- create an extra "empty" block for the master-only vars //--- since I don't know what OSI will do with empty problem //--- we will make column bounds explicity rows //--- int nMasterOnlyCols = static_cast<int> (modelCore->masterOnlyCols.size()); if (nMasterOnlyCols) { if (m_appParam.LogLevel >= 1) (*m_osLog) << "Create model part Master-Only." << endl; createModelMasterOnlys2(modelCore->masterOnlyCols); } UtilPrintFuncBegin(m_osLog, m_classTag, "printCurrentProblem()", m_appParam.LogLevel, 2); //free local memory UTIL_DELARR( rowsCore); }//end try catch(const ErrorClass& eclass){ throw ErrorClass( eclass.errormsg); } }// end createModels()
//===========================================================================// void MCF_DecompApp::createModels() { //--- //--- This function does the work to create the different models //--- that will be used. This memory is owned by the user. It will //--- be passed to the application interface and used by the algorithms. //--- UtilPrintFuncBegin(m_osLog, m_classTag, "createModels()", m_appParam.LogLevel, 2); //--- //--- (Integer) Multi-Commodity Flow Problem (MCF). //--- //--- We are given: //--- (1) a directed graph G=(N,A), //--- (2) a set of commodities K, where each commodity is //--- a source-sink pair. //--- //--- min sum{k in K} sum{(i,j) in A} w[i,j] x[k,i,j] //--- s.t. sum{(j,i) in A} x[k,i,j] - //--- sum{(i,j) in A} x[k,i,j] = d[i,k], for all i in N, k in K //--- sum{k in K} x[k,i,j] >= l[i,j], for all (i,j) in A //--- sum{k in K} x[k,i,j] <= u[i,j], for all (i,j) in A //--- x[k,i,j] integer >= l[i,j] <= u[i,j], for all (i,j) in A //--- For k=(s,t) in K, //--- d[i,k] = -d[k] if i=s //--- = d[k] if i=t //--- = 0, otherwise //--- //--- NOTE: to make sure the problem is always feasible, dummy arcs //--- have been added between all source-sink commodity pairs and have //--- been given a 'big' weight. //--- //--- //--- The decomposition is formed as: //--- //--- MASTER (A''): //--- sum{k in K} x[k,i,j] >= l[i,j], for all (i,j) in A //--- sum{k in K} x[k,i,j] <= u[i,j], for all (i,j) in A //--- x[k,i,j] integer >= l[i,j] <= u[i,j], for all (i,j) in A //--- //--- SUBPROBLEM (A'): (one block for each k in K) //--- sum{(j,i) in A} x[k,i,j] - //--- sum{(i,j) in A} x[k,i,j] = d[i,k], for all i in N //--- x[k,i,j] integer >= l[i,j] <= u[i,j], for all (i,j) in A //--- //--- //--- Get information about this problem instance. //--- int k, a, colIndex; int numCommodities = m_instance.m_numCommodities; int numArcs = m_instance.m_numArcs; int numCols = numCommodities * numArcs; MCF_Instance::arc* arcs = m_instance.m_arcs; //--- //--- Construct the objective function and set it //--- columns indexed as [k,a]= k*numArcs + a //--- objective = new double[numCols]; if (!objective) { throw UtilExceptionMemory("createModels", "MCF_DecompApp"); } colIndex = 0; for (k = 0; k < numCommodities; k++) for (a = 0; a < numArcs; a++) { objective[colIndex++] = arcs[a].weight; } //--- //--- set the objective //--- setModelObjective(objective, numCols); //--- //--- create the core/master model and set it //--- modelCore = new DecompConstraintSet(); createModelCore(modelCore); setModelCore(modelCore, "core"); //--- //--- create the relaxed/subproblem models and set them //--- for (k = 0; k < numCommodities; k++) { modelRelax = new DecompConstraintSet(); string modelName = "relax" + UtilIntToStr(k); if (m_appParam.UseSparse) { createModelRelaxSparse(modelRelax, k); } else { createModelRelax(modelRelax, k); } setModelRelax(modelRelax, modelName, k); m_models.push_back(modelRelax); } UtilPrintFuncEnd(m_osLog, m_classTag, "createModels()", m_appParam.LogLevel, 2); }
/** * Called to create the core and relaxation models */ void DippyDecompApp::createModels() { int i, len; string name; // create the core model DecompConstraintSet* modelCore = new DecompConstraintSet(); // gets the master problem model PyObject* pMasterAsTuple = PyObject_CallMethod(m_pProb, "getMasterAsTuple", NULL); if (pMasterAsTuple == NULL) { throw UtilException("Error calling method prob.getMasterAsTuple()", "createModels", "DippyDecompApp"); } PyObject* pObjective = PyTuple_GetItem(pMasterAsTuple, 0); PyObject* pRowList = PyTuple_GetItem(pMasterAsTuple, 1); PyObject* pColList = PyTuple_GetItem(pMasterAsTuple, 2); m_rowList = pRowList; Py_XINCREF(m_rowList); m_numCols = PyObject_Length(pColList); m_colList = pColList; Py_XINCREF(m_colList); int numRows = PyObject_Length(pRowList); PyObject* pRow, *pRowName, *pRowLb, *pRowUb; double lb, ub; for (int i = 0; i < numRows; i++) { pRow = PyList_GetItem(pRowList, i); pRowName = PyObject_CallMethod(pRow, "getName", NULL); if (pRowName == NULL) { throw UtilException("Error calling method row.getName()", "createModels", "DippyDecompApp"); } pRowLb = PyObject_CallMethod(pRow, "getLb", NULL); if (pRowLb == NULL) { throw UtilException("Error calling method row.getLb()", "createModels", "DippyDecompApp"); } pRowUb = PyObject_CallMethod(pRow, "getUb", NULL); if (pRowUb == NULL) { throw UtilException("Error calling method row.getUb()", "createModels", "DippyDecompApp"); } name = PyString_AsString(pRowName); if (pRowLb == Py_None) { lb = -m_infinity; } else { lb = PyFloat_AsDouble(pRowLb); } if (pRowUb == Py_None) { ub = m_infinity; } else { ub = PyFloat_AsDouble(pRowUb); } modelCore->rowNames.push_back(name); modelCore->rowLB.push_back(lb); modelCore->rowUB.push_back(ub); m_rowIndices[pRow] = i; // Don't need to increase reference count here as m_rowList // references pRow } PyObject* pCol, *pColLb, *pColUb, *pIsInt; for (int j = 0; j < m_numCols; j++) { pCol = PyList_GetItem(pColList, j); PyObject* pColName = PyObject_CallMethod(pCol, "getName", NULL); if (pColName == NULL) { throw UtilException("Error calling method col.getName()", "createModels", "DippyDecompApp"); } pColLb = PyObject_CallMethod(pCol, "getLb", NULL); if (pColLb == NULL) { throw UtilException("Error calling method col.getLb()", "createModels", "DippyDecompApp"); } pColUb = PyObject_CallMethod(pCol, "getUb", NULL); if (pColUb == NULL) { throw UtilException("Error calling method col.getUb()", "createModels", "DippyDecompApp"); } pIsInt = PyObject_CallMethod(pCol, "isInteger", NULL); if (pIsInt == NULL) { throw UtilException("Error calling method col.isInteger()", "createModels", "DippyDecompApp"); } name = PyString_AsString(pColName); if (pColLb == Py_None) { lb = -m_infinity; } else { lb = PyFloat_AsDouble(pColLb); } if (pColUb == Py_None) { ub = m_infinity; } else { ub = PyFloat_AsDouble(pColUb); } modelCore->colNames.push_back(name); modelCore->colLB.push_back(lb); modelCore->colUB.push_back(ub); if (PyObject_IsTrue(pIsInt)) { modelCore->integerVars.push_back(j); } m_colIndices[pCol] = j; // Don't need to increase reference count here // as m_rowList references pCol } // set objective coefficients double* obj = new double[m_numCols]; UtilFillN(obj, m_numCols, 0.0); PyObject* pObjKeys = PyDict_Keys(pObjective); PyObject* pCoeff; for (int j = 0; j < PyObject_Length(pObjKeys); j++) { pCol = PyList_GetItem(pObjKeys, j); pCoeff = PyDict_GetItem(pObjective, pCol); obj[m_colIndices[pCol]] = PyFloat_AsDouble(pCoeff); } setModelObjective(obj, m_numCols); // set constraint matrix modelCore->M = pyConstraints_AsPackedMatrix(pRowList, m_rowIndices, m_colIndices); modelCore->M->setDimensions(modelCore->rowLB.size(), modelCore->colLB.size()); // subproblems PyObject* pRelaxedDict = PyObject_CallMethod(m_pProb, "getRelaxsAsDict", NULL); if (pRelaxedDict == NULL) { throw UtilException("Error calling method prob.getRelaxsAsDict()", "createModels", "DippyDecompApp"); } int* masterOnly = new int[m_numCols]; if (!masterOnly) { throw UtilExceptionMemory("createModels", "DecompApp"); } UtilFillN(masterOnly, m_numCols, 1); int nRelaxed = 0; if (pRelaxedDict != Py_None) { nRelaxed = PyObject_Length(pRelaxedDict); } // we have a list of relaxations m_relaxedKeys = PyDict_Keys(pRelaxedDict); Py_XINCREF(m_relaxedKeys); PyObject* pKey, *pRelax; for (int p = 0; p < nRelaxed; p++) { DecompConstraintSet* modelRelax = new DecompConstraintSet(); // each relaxation is a LpProblem pKey = PyList_GetItem(m_relaxedKeys, p); pRelax = PyDict_GetItem(pRelaxedDict, pKey); m_relaxIndices[pKey] = p; // Don't need to increase reference count here //as m_relaxedKey references pKey PyObject* pRelaxAsTuple = PyObject_CallMethod(m_pProb, "getRelaxAsTuple", "O", pRelax); if (pRelaxAsTuple == NULL) { throw UtilException("Error calling method prob.getRelaxAsTuple()", "createModels", "DippyDecompApp"); } // row names pRowList = PyTuple_GetItem(pRelaxAsTuple, 0); pColList = PyTuple_GetItem(pRelaxAsTuple, 1); numRows = PyObject_Length(pRowList); map<PyObject*, int> relaxRowIndices; for (int i = 0; i < numRows; i++) { pRow = PyList_GetItem(pRowList, i); pRowName = PyObject_CallMethod(pRow, "getName", NULL); if (pRowName == NULL) { throw UtilException("Error calling method row.getName()", "createModels", "DippyDecompApp"); } pRowLb = PyObject_CallMethod(pRow, "getLb", NULL); if (pRowLb == NULL) { throw UtilException("Error calling method row.getLb()", "createModels", "DippyDecompApp"); } pRowUb = PyObject_CallMethod(pRow, "getUb", NULL); if (pRowUb == NULL) { throw UtilException("Error calling method row.getUb()", "createModels", "DippyDecompApp"); } name = PyString_AsString(pRowName); if (pRowLb == Py_None) { lb = -m_infinity; } else { lb = PyFloat_AsDouble(pRowLb); } if (pRowUb == Py_None) { ub = m_infinity; } else { ub = PyFloat_AsDouble(pRowUb); } modelRelax->rowNames.push_back(name); modelRelax->rowLB.push_back(lb); modelRelax->rowUB.push_back(ub); relaxRowIndices[pRow] = i; } // get the constraint matrix for this relaxation modelRelax->M = pyConstraints_AsPackedMatrix(pRowList, relaxRowIndices, m_colIndices); // set all cols at their lower bounds for (int j = 0; j < modelCore->colLB.size(); j++) { modelRelax->colLB.push_back(modelCore->colLB[j]); modelRelax->colUB.push_back(modelCore->colLB[j]); } // get active cols int cols = PyObject_Length(pColList); int index; for (int j = 0; j < cols; j++) { pCol = PyList_GetItem(pColList, j); index = m_colIndices[pCol]; if ( (index < 0) || (index >= m_colIndices.size()) ) { throw UtilException("Bad index for " + name, "createModels", "DippyDecompApp"); } modelRelax->colUB[index] = modelCore->colUB[index]; modelRelax->activeColumns.push_back(index); masterOnly[index] = 0; } modelRelax->M->setDimensions(modelRelax->rowLB.size(), modelRelax->colLB.size()); // copy integer vars (from master prob) for (int j = 0; j < modelCore->integerVars.size(); j++) { modelRelax->integerVars.push_back(modelCore->integerVars[j]); } setModelRelax(modelRelax, "BLOCK", p); } for (i = 0; i < m_numCols; i++) { if (masterOnly[i]){ modelCore->masterOnlyCols.push_back(i); } } printf("Num master-only cols: %d\n", modelCore->masterOnlyCols.size()); // set the core problem setModelCore(modelCore, "CORE"); UTIL_DELARR(masterOnly); }
//===========================================================================// void SDPUC_DecompApp::createModels(){ //--- //--- This function does the work to create the different models //--- that will be used. This memory is owned by the user. It will //--- be passed to the application interface and used by the algorithms. //--- UtilPrintFuncBegin(m_osLog, m_classTag, "createModels()", m_appParam.LogLevel, 2); //--- //--- Switched Dispatch Problem with Unit Commitment (SDPUC). //--- //--- We are given: //--- (1) a directed graph G=(N,A), //--- (2) a set of time periods T, //--- //--- min sum{(i,j) in A} f1[i,j] y1[i,j] //--- + sum{t in T} sum{(i,j) in A} f2[i,j] y2[i,j,t] + c[i,j,t] x[i,j,t] //--- s.t. sum{(j,i) in A} x[i,j,t] - //--- sum{(i,j) in A} x[i,j,t] = d[i,t], for all i in N, t in T //--- x[i,j,t] >= l[i,j,t] z[i,j,t], for all (i,j) in A, t in T //--- x[i,j,t] <= u[i,j,t] z[i,j,t], for all (i,j) in A, t in T //--- r[i,j] x[i,j,t] - theta[j] + theta[i] <= M (1 - z[i,j,t]) for all i,j,t //--- r[i,j] x[i,j,t] - theta[j] + theta[i] >= -M (1 - z[i,j,t]) for all i,j,t //--- z[i,j,t] <= y1[i,j] for all (i,j) in A, t in T //arc-investment //--- z[i,j,t] - z[i,j,t-1] <= y2[i,j,t] for all (i,j) in A, t in T //arc(unit) commitment //--- y[i,j] binary for all (i,j) in A //--- //--- NOTE: to make sure the problem is always feasible, //---- demand may have to be modelled as arcs with large negative costs //--- //--- //--- The decomposition is formed as: //--- //--- MASTER (A''): //--- z[i,j,t] <= y1[i,j] for all (i,j) in A, t in T //arc-investment //--- z[i,j,t] - z[i,j,t-1] <= y2[i,j,t] for all (i,j) in A, t in T //arc(unit) commitment //--- y[i,j] binary for all (i,j) in A //--- //--- SUBPROBLEM (A'): (one block for each t in T) //--- sum{(j,i) in A} x[i,j,t] - //--- sum{(i,j) in A} x[i,j,t] = d[i,t], for all i in N //--- x[i,j,t] >= l[i,j,t] z[i,j,t], for all (i,j) in A //--- x[i,j,t] <= u[i,j,t] z[i,j,t], for all (i,j) in A //--- r[i,j] x[i,j,t] - theta[j] + theta[i] <= M (1 - z[i,j,t]) for all i,j //--- r[i,j] x[i,j,t] - theta[j] + theta[i] >= -M (1 - z[i,j,t]) for all i,j //--- //--- //--- Get information about this problem instance. //--- int i, t, a, colIndex; int numTimeperiods = m_instance.m_numTimeperiods; int numArcs = m_instance.m_numArcs; int numNodes = m_instance.m_numNodes; int numCols = numArcs //y1-vars + 3 * numTimeperiods * numArcs //y2-, z-, and x-vars + numTimeperiods * numNodes; //theta-vars SDPUC_Instance::arc * arcs = m_instance.m_arcs; SDPUC_Instance::timeseries * ts = m_instance.m_timeseries; cout << "\nnumCols=" << numCols << " numTimePeriods=" << numTimeperiods; cout << "numNodes=" << numNodes << " numArcs=" << numArcs << endl; //--- //--- Construct the objective function and set it //--- y1-var columns indexed as [a] = a in [0 ; numArcs-1] //--- y2-var columns indexed as [a,t] = a + numArcs in [numArcs ; numArcs * (1 + numTimeperiods) - 1] //--- z-var columns indexed as [a,t] = t*numArcs + a + numArcs * (1 + numTimeperiods) //--- in [numArcs*(1+numTimeperiods); numArcs*(1 + 2*numTimeperiods) - 1] //--- x-var columns indexed as [a,t] = t*numArcs + a + numArcs*(1 + 2*numTimeperiods) , //--- in [numArcs*(1 + 2*numTimeperiods) ; numArcs*(1 + 3*numTimeperiods) - 1] //--- theta-var columns indexed as [i,t] = t*numNodes + i + numArcs*(1 + 3*numTimeperiods) , //--- in [numArcs*(1 + 3*numTimeperiods) ; numArcs*(1 + 3*numTimeperiods) + numNodes*numTimeperiods - 1] //-- m_objective = new double[numCols]; //initialise to 0 for(i = 0; i < numCols; i++){ m_objective[i] = 0; } if(!m_objective) throw UtilExceptionMemory("createModels", "MCF_DecompApp"); colIndex = 0; for(a = 0; a < numArcs; a++) { m_objective[colIndex++] = arcs[a].fcost1; //fixed arc investment cost } for(t = 0; t < numTimeperiods; t++) { for(a = 0; a < numArcs; a++) { m_objective[colIndex++] = arcs[a].fcost2; //fixed arc "start-up" cost } } colIndex = numArcs*(1 + 2*numTimeperiods); //start-index for x-vars for(t = 0; t < numTimeperiods; t++) { for(a = 0; a < numArcs; a++) { m_objective[colIndex++] = arcs[a].mcost * ts[0].values[t] ; //arc cost * probability (assume ts[0] indicate timeperiod probabilities) } } //--- //--- set the objective //--- setModelObjective(m_objective, numCols); /*cout << "obj = " ; for(i = 0; i < numCols; i++){ cout << m_objective[i] << " "; } cout << endl;*/ //--- //--- create the core/master model and set it //--- DecompConstraintSet * modelCore = new DecompConstraintSet(); createModelCore(modelCore); setModelCore(modelCore, "core"); //--- //--- create the relaxed/subproblem models and set them //--- for(t = 0; t < numTimeperiods; t++){ DecompConstraintSet * modelRelax = new DecompConstraintSet(); string modelName = "relax" + UtilIntToStr(t); if(m_appParam.UseSparse) createModelRelaxSparse(modelRelax, t); else createModelRelax(modelRelax, t); setModelRelax(modelRelax, modelName, t); } //--- //--- create an extra "empty" block for the master-only vars //--- since I don't know what OSI will do with empty problem //--- we will make column bounds explicity rows //--- UtilPrintFuncEnd(m_osLog, m_classTag, "createModels()", m_appParam.LogLevel, 2); }