//===========================================================================// void GAP_Instance::readInstance(string& fileName) { int i, j, n_ij, indexIJ; ifstream is; //--- //--- File format (.../Decomp/data/GAP) //--- //--- agents = machines (m, i index) //--- jobs = tasks (n, j index) //--- //--- number of machines (m), number of tasks (n) //--- for each machine i (i=1,...,m) in turn: //--- cost of allocating task j to machine i (j=1,...,n) //--- for each machine i (i=1,...,m) in turn: //--- resource consumed in allocating task j to machine i (j=1,...,n) //--- resource capacity of machine j (j=1,...,m) //--- UtilOpenFile(is, fileName.c_str()); is >> m_nMachines >> m_nTasks; //--- //--- allocate memory for capacity, value and weight //--- n_ij = m_nMachines * m_nTasks; m_capacity = new int[m_nMachines]; m_profit = new int[n_ij]; m_weight = new int[n_ij]; if (!(m_capacity && m_profit && m_weight)) { throw UtilExceptionMemory("readInstance", "GAP_Instance"); } indexIJ = 0; for (i = 0; i < m_nMachines; i++) { for (j = 0; j < m_nTasks; j++) { is >> m_profit[indexIJ++];//TODO: bad name - since cost } } indexIJ = 0; for (i = 0; i < m_nMachines; i++) { for (j = 0; j < m_nTasks; j++) { is >> m_weight[indexIJ++]; } } for (j = 0; j < m_nMachines; j++) { is >> m_capacity[j]; } is.close(); }
//===========================================================================// 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); }
//===========================================================================// void OSDipApp::createModelPart(DecompConstraintSet * model, const int nRowsPart, const int * rowsPart) { const int nCols = m_osInterface.getVariableNumber(); const double * rowLB = m_osInterface.getRowLower(); const double * rowUB = m_osInterface.getRowUpper(); const double * colLB = m_osInterface.getColLower(); const double * colUB = m_osInterface.getColUpper(); const char * integerVars = m_osInterface.getIntegerColumns(); std::cout << "STARTING createModelPart" << std::endl; model->M = new CoinPackedMatrix(false, 0.0, 0.0); if (!model->M) throw UtilExceptionMemory("createModels", "OSDipApp"); model->reserve(nRowsPart, nCols); model->M->submatrixOf(*m_osInterface.m_coinpm, nRowsPart, rowsPart); //--- //--- set the row upper and lower bounds //--- set the col upper and lower bounds //--- m_appParam.UseNames = true; int i, r; for (i = 0; i < nRowsPart; i++) { r = rowsPart[i]; if (m_appParam.UseNames == true) { const char * rowName = m_osInterface.getConstraintNames()[r].c_str(); // std::cout << "Row Name = " << m_osInterface.getConstraintNames()[r] << std::endl; if (rowName) model->rowNames.push_back(rowName); //std::cout << "Row Name = " << m_osInterface.getConstraintNames()[r] << std::endl; } model->rowLB.push_back(rowLB[r]); model->rowUB.push_back(rowUB[r]); } copy(colLB, colLB + nCols, back_inserter(model->colLB)); copy(colUB, colUB + nCols, back_inserter(model->colUB)); //--- //--- big fat hack... we don't deal with dual rays yet, //--- so, we assume subproblems are bounded //--- //--- NOTE: might also need to tighten LBs //--- //--- Too small - ATM infeasible! //--- Too big - round off issues with big coeffs in //--- master-only vars //--- //--- TODO: need extreme rays or bounded subproblems from user //--- if (m_appParam.ColumnUB < 1.0e15) { for (i = 0; i < nCols; i++) { if (colUB[i] > 1.0e15) { model->colUB[i] = m_appParam.ColumnUB; } } } if (m_appParam.ColumnLB > -1.0e15) { for (i = 0; i < nCols; i++) { if (colLB[i] < -1.0e15) { model->colLB[i] = m_appParam.ColumnLB; } } } //--- //--- set the indices of the integer variables of modelRelax //--- also set the column names, if they exist //--- for (i = 0; i < nCols; i++) { if (m_appParam.UseNames == true) { //const char * colName = m_osInterface.columnName(i); const char * colName = m_osInterface.getVariableNames()[i].c_str(); if (colName) model->colNames.push_back(colName); } if ( (integerVars != NULL) && integerVars[i] == '1' ) { //std::cout << "WE HAVE AN INTEGER VARIABLE " << std::endl; model->integerVars.push_back(i); } } //free local memory UTIL_DELARR( integerVars); }
//===========================================================================// void OSDipApp::createModelPartSparse(DecompConstraintSet * model, const int nRowsPart, const int * rowsPart) { const int nColsOrig = m_osInterface.getVariableNumber(); const double * rowLB = m_osInterface.getRowLower(); const double * rowUB = m_osInterface.getRowUpper(); const double * colLB = m_osInterface.getColLower(); const double * colUB = m_osInterface.getColUpper(); const char * integerVars = m_osInterface.getIntegerColumns(); //--- //--- set model as sparse //--- model->setSparse(nColsOrig); int nCols, origIndex, newIndex; vector<int>::iterator vit; newIndex = 0; for (vit = model->activeColumns.begin(); vit != model->activeColumns.end(); vit++) { origIndex = *vit; //std::cout << "lower bound = " << colLB[origIndex] << std::endl; //std::cout << "upper bound = " << colUB[origIndex] << std::endl; model->pushCol(colLB[origIndex], colUB[origIndex], integerVars[origIndex] == '0' ? false : true, origIndex); if(integerVars[origIndex] == 0) std::cout << "HERE I AM" << std::endl; //--- //--- big fat hack... we don't deal with dual rays yet, //--- so, we assume subproblems are bounded //--- if (m_appParam.ColumnUB < 1.0e15) { if (colUB[origIndex] > 1.0e15) { model->colUB[newIndex] = m_appParam.ColumnUB; } } if (m_appParam.ColumnLB > -1.0e15) { if (colLB[origIndex] < -1.0e15) { model->colLB[newIndex] = m_appParam.ColumnLB; } } if (m_appParam.UseNames) { //const char * colName = m_osInterface.columnName(origIndex); const char * colName = m_osInterface.getConstraintNames()[origIndex].c_str(); if (colName) model->colNames.push_back(colName); } newIndex++; } nCols = static_cast<int> (model->activeColumns.size()); assert(static_cast<int> (model->colLB.size()) == nCols); assert(static_cast<int> (model->colUB.size()) == nCols); model->M = new CoinPackedMatrix(false, 0.0, 0.0); if (!model->M) throw UtilExceptionMemory("createModels", "OSDipApp"); model->M->setDimensions(0, nCols); model->reserve(nRowsPart, nCols); //--- //--- for each row in rowsPart, create the row using sparse mapping //--- int i, k, r, begInd; const map<int, int> & origToSparse = model->getMapOrigToSparse(); const CoinPackedMatrix * M = m_osInterface.getCoinPackedMatrix(); const int * matInd = M->getIndices(); const CoinBigIndex * matBeg = M->getVectorStarts(); const int * matLen = M->getVectorLengths(); const double * matVal = M->getElements(); const int * matIndI = NULL; const double * matValI = NULL; vector<CoinBigIndex> & rowBeg = model->m_rowBeg;//used as temp vector<int> & rowInd = model->m_rowInd;//used as temp vector<double> & rowVal = model->m_rowVal;//used as temp map<int, int>::const_iterator mit; begInd = 0; rowBeg.push_back(0); for (i = 0; i < nRowsPart; i++) { r = rowsPart[i]; if (m_appParam.UseNames) { const char * rowName = m_osInterface.getConstraintNames()[r].c_str(); if (rowName) model->rowNames.push_back(rowName); } model->rowLB.push_back(rowLB[r]); model->rowUB.push_back(rowUB[r]); matIndI = matInd + matBeg[r]; matValI = matVal + matBeg[r]; for (k = 0; k < matLen[r]; k++) { origIndex = matIndI[k]; mit = origToSparse.find(origIndex); assert(mit != origToSparse.end()); rowInd.push_back(mit->second); rowVal.push_back(matValI[k]); } begInd += matLen[r]; rowBeg.push_back(begInd); } model->M->appendRows(nRowsPart, &rowBeg[0], &rowInd[0], &rowVal[0]); //free local memory rowBeg.clear(); rowInd.clear(); rowVal.clear(); UTIL_DELARR( integerVars); }
//===========================================================================// void MCF_DecompApp::createModelRelaxSparse(DecompConstraintSet* model, int commId) { //--- //--- 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 //--- For k=(s,t) in K, //--- d[i,k] = -d[k] if i=s //--- = d[k] if i=t //--- = 0, otherwise //--- int a, i, head, tail, origColIndex, source, sink; int numArcs = m_instance.m_numArcs; int numNodes = m_instance.m_numNodes; int numCommodities = m_instance.m_numCommodities; int numCols = numArcs; int numRows = numNodes; int numColsOrig = numArcs * numCommodities; MCF_Instance::arc* arcs = m_instance.m_arcs; MCF_Instance::commodity* commodities = m_instance.m_commodities; UtilPrintFuncBegin(m_osLog, m_classTag, "createModelRelaxSparse()", m_appParam.LogLevel, 2); //--- //--- create space for the model matrix (row-majored) //--- model->M = new CoinPackedMatrix(false, 0.0, 0.0); if (!model->M) { throw UtilExceptionMemory("createModelCore", "MCF_DecompApp"); } model->M->setDimensions(0, numCols); model->reserve(numRows, numCols); model->setSparse(numColsOrig); //--- //--- get this commodity's source and sink node //--- source = commodities[commId].source; sink = commodities[commId].sink; //--- //--- create the rows //--- NOTE: this is somewhat inefficient (but simple) //--- for (i = 0; i < numNodes; i++) { CoinPackedVector row; for (a = 0; a < numArcs; a++) { tail = arcs[a].tail; head = arcs[a].head; if (head == i) { row.insert(a, 1.0); } else if (tail == i) { row.insert(a, -1.0); } } if (i == source) model->appendRow(row, -commodities[commId].demand, -commodities[commId].demand); else if (i == sink) model->appendRow(row, commodities[commId].demand, commodities[commId].demand); else { model->appendRow(row, 0.0, 0.0); } } //--- //--- set the colLB, colUB, integerVars and sparse mapping //--- origColIndex = commId * numArcs; for (a = 0; a < numArcs; a++) { double arcLB = arcs[a].lb; double arcUB = arcs[a].ub; model->pushCol(arcLB, arcUB, true, origColIndex); origColIndex++; } UtilPrintFuncEnd(m_osLog, m_classTag, "createModelRelaxSparse()", m_appParam.LogLevel, 2); }
//===========================================================================// 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); }
//===========================================================================// void MCF_DecompApp::createModelCore(DecompConstraintSet* model) { //--- //--- 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 //--- int k, a, colIndex; int numCommodities = m_instance.m_numCommodities; int numArcs = m_instance.m_numArcs; int numCols = numCommodities * numArcs; int numRows = 2 * numArcs; MCF_Instance::arc* arcs = m_instance.m_arcs; UtilPrintFuncBegin(m_osLog, m_classTag, "createModelCore()", m_appParam.LogLevel, 2); //--- //--- create space for the model matrix (row-majored) //--- model->M = new CoinPackedMatrix(false, 0.0, 0.0); if (!model->M) { throw UtilExceptionMemory("createModelCore", "MCF_DecompApp"); } model->M->setDimensions(0, numCols); model->reserve(numRows, numCols); //--- //--- create the rows and set the col/row bounds //--- UtilFillN(model->colLB, numCols, 0.0); UtilFillN(model->colUB, numCols, m_infinity); for (a = 0; a < numArcs; a++) { CoinPackedVector row; double arcLB = arcs[a].lb; double arcUB = arcs[a].ub; for (k = 0; k < numCommodities; k++) { colIndex = k * numArcs + a; model->colLB[colIndex] = arcLB; model->colUB[colIndex] = arcUB; row.insert(colIndex, 1.0); } //TODO: any issue with range constraints? model->appendRow(row, -m_infinity, arcUB); string rowNameUB = "capUB(" + UtilIntToStr(a) + "_" + UtilIntToStr(arcs[a].tail) + "," + UtilIntToStr(arcs[a].head) + ")"; model->rowNames.push_back(rowNameUB); model->appendRow(row, arcLB, m_infinity); string rowNameLB = "capLB(" + UtilIntToStr(a) + "_" + UtilIntToStr(arcs[a].tail) + "," + UtilIntToStr(arcs[a].head) + ")"; model->rowNames.push_back(rowNameLB); } //--- //--- create column names (helps with debugging) //--- for (k = 0; k < numCommodities; k++) { for (a = 0; a < numArcs; a++) { string colName = "x(comm_" + UtilIntToStr(k) + "," + UtilIntToStr(a) + "_" + UtilIntToStr(arcs[a].tail) + "," + UtilIntToStr(arcs[a].head) + ")"; model->colNames.push_back(colName); } } //--- //--- set the indices of the integer variables of model //--- UtilIotaN(model->integerVars, numCols, 0); UtilPrintFuncEnd(m_osLog, m_classTag, "createModelCore()", m_appParam.LogLevel, 2); }
//===========================================================================// void MCF_DecompApp::createModelRelax(DecompConstraintSet* model, int commId) { //--- //--- 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 //--- For k=(s,t) in K, //--- d[i,k] = -d[k] if i=s //--- = d[k] if i=t //--- = 0, otherwise //--- int a, i, head, tail, colIndex, source, sink; int numCommodities = m_instance.m_numCommodities; int numArcs = m_instance.m_numArcs; int numNodes = m_instance.m_numNodes; int numCols = numCommodities * numArcs; int numRows = numNodes; MCF_Instance::arc* arcs = m_instance.m_arcs; MCF_Instance::commodity* commodities = m_instance.m_commodities; UtilPrintFuncBegin(m_osLog, m_classTag, "createModelRelax()", m_appParam.LogLevel, 2); //--- //--- create space for the model matrix (row-majored) //--- model->M = new CoinPackedMatrix(false, 0.0, 0.0); if (!model->M) { throw UtilExceptionMemory("createModelCore", "MCF_DecompApp"); } model->M->setDimensions(0, numCols); model->reserve(numRows, numCols); //--- //--- get this commodity's source and sink node //--- source = commodities[commId].source; sink = commodities[commId].sink; //--- //--- create the rows //--- NOTE: this is somewhat inefficient (but simple) //--- for (i = 0; i < numNodes; i++) { CoinPackedVector row; for (a = 0; a < numArcs; a++) { tail = arcs[a].tail; head = arcs[a].head; if (head == i) { colIndex = commId * numArcs + a; row.insert(colIndex, 1.0); } else if (tail == i) { colIndex = commId * numArcs + a; row.insert(colIndex, -1.0); } } if (i == source) model->appendRow(row, -commodities[commId].demand, -commodities[commId].demand); else if (i == sink) model->appendRow(row, commodities[commId].demand, commodities[commId].demand); else { model->appendRow(row, 0.0, 0.0); } string rowName = "flow(" + UtilIntToStr(commId) + "_" + UtilIntToStr(i) + "_" + UtilIntToStr(source) + "," + UtilIntToStr(sink) + ")"; model->rowNames.push_back(rowName); } //--- //--- create a list of the "active" columns (those related //--- to this commmodity) all other columns are fixed to 0 //--- UtilFillN(model->colLB, numCols, 0.0); UtilFillN(model->colUB, numCols, 0.0); colIndex = commId * numArcs; for (a = 0; a < numArcs; a++) { double arcLB = arcs[a].lb; double arcUB = arcs[a].ub; model->colLB[colIndex] = arcLB; model->colUB[colIndex] = arcUB; model->activeColumns.push_back(colIndex); colIndex++; } //--- //--- set the indices of the integer variables of model //--- UtilIotaN(model->integerVars, numCols, 0); UtilPrintFuncEnd(m_osLog, m_classTag, "createModelRelax()", 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); }
//===========================================================================// void SDPUC_DecompApp::createModelRelax(DecompConstraintSet * model, int tpId){ //--- //--- 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 //--- For k=(s,t) in K, //--- d[i,k] = -d[k] if i=s //--- = d[k] if i=t //--- = 0, otherwise //--- 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\{s}, where s is the super source //--- 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 in A //--- r[i,j] x[i,j,t] - theta[j] + theta[i] >= -M (1 - z[i,j,t]) for all i,j in A //--- int a, i, j, head, tail, colIndex, source; int numTimeperiods = m_instance.m_numTimeperiods; int numArcs = m_instance.m_numArcs; int numSwitchings = m_instance.m_numSwitchings; 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::node * nodes = m_instance.m_nodes; SDPUC_Instance::timeseries * ts = m_instance.m_timeseries; int numACArcs = 0; for(a = 0; a < numArcs; a++){ if(arcs[a].acline == 1) { numACArcs++; } } int numRows = numNodes - 1 // balance + 2 * numArcs // capacity + 2 * numACArcs // and kirchoffs constraints + 1; // max. allowed no. of switches employed sum{z} <= k int col_yStartIndex = 0; int col_zStartIndex = numArcs*(1+numTimeperiods); int col_xStartIndex = numArcs * (1 + 2*numTimeperiods); int col_thetaStartIndex = numArcs*(1 + 3*numTimeperiods) ; double bigM = 100; UtilPrintFuncBegin(m_osLog, m_classTag, "createModelRelax()", m_appParam.LogLevel, 2); //--- //--- create space for the model matrix (row-majored) //--- model->M = new CoinPackedMatrix(false, 0.0, 0.0); if(!model->M) throw UtilExceptionMemory("createModelCore", "MCF_DecompApp"); model->M->setDimensions(0, numCols); model->reserve(numRows, numCols); //--- //--- set super source node //--- source = 0; //--- //--- create the rows //--- NOTE: this is somewhat inefficient (but simple) //--- int hej = 0; cout << "Generating sub-problem " << tpId << endl; hej++; //cout << "y_index = " << col_yStartIndex << endl; //cout << "z_index = " << col_zStartIndex << endl; //cout << "x_index = " << col_xStartIndex << endl; //cout << "theta_index = " << col_thetaStartIndex << endl; //--- create balance constraints for(i = 0; i < numNodes; i++){ CoinPackedVector row; for(a = 0; a < numArcs; a++){ tail = arcs[a].tail; head = arcs[a].head; if(head == i){ colIndex = col_xStartIndex + tpId * numArcs + a; row.insert(colIndex, 1.0); } else if(tail == i){ colIndex = col_xStartIndex + tpId * numArcs + a; row.insert(colIndex, -1.0); } } //set demand d double d = nodes[i].demand * ts[nodes[i].tsdemand].values[tpId]; std::string rowName = "balance_" + UtilIntToStr(i) + "_" + UtilIntToStr(tpId); if(i == source) { model->appendRow(row, -m_infinity, 0.0, rowName); } else { model->appendRow(row, d, d, rowName); } } //--- create capacity constraints and kirchoffs constraints for(a = 0; a < numArcs; a++){ CoinPackedVector rowLB, rowUB; //lower-, and upperbound //for(a = 0; a < numArcs; a++){ tail = arcs[a].tail; head = arcs[a].head; double lb = arcs[a].lb * ts[arcs[a].tscap].values[tpId]; double ub = arcs[a].ub * ts[arcs[a].tscap].values[tpId]; double reactance = arcs[a].weight; colIndex = col_zStartIndex + tpId * numArcs + a; rowLB.insert(colIndex, -lb); rowUB.insert(colIndex, -ub); colIndex = col_xStartIndex + tpId * numArcs + a; rowLB.insert(colIndex, 1.0); rowUB.insert(colIndex, 1.0); //set flow lower and upperbound std::string rowNameLB = "lb_" + UtilIntToStr(a) + "_" + UtilIntToStr(tpId); std::string rowNameUB = "ub_" + UtilIntToStr(a) + "_" + UtilIntToStr(tpId); model->appendRow(rowLB, 0.0, m_infinity, rowNameLB); model->appendRow(rowUB, -m_infinity, 0.0, rowNameUB); //set kirchoffs voltage constraints for ac-arcs if(arcs[a].acline == 1) { CoinPackedVector rowK1, rowK2; //Kirchoff1, and Kirchoff2 colIndex = col_zStartIndex + tpId * numArcs + a; rowK1.insert(colIndex, bigM); rowK2.insert(colIndex, -bigM); colIndex = col_xStartIndex + tpId * numArcs + a; rowK1.insert(colIndex, reactance); rowK2.insert(colIndex, reactance); for(i = 0; i < numNodes; i++){ if(head == i){ colIndex = col_thetaStartIndex + tpId * numNodes + i; rowK1.insert(colIndex, -1.0); rowK2.insert(colIndex, -1.0); } else if(tail == i){ colIndex = col_thetaStartIndex + tpId * numNodes + i; rowK1.insert(colIndex, 1.0); rowK2.insert(colIndex, 1.0); } } std::string rowNameK1 = "k1_" + UtilIntToStr(a) + "_" + UtilIntToStr(tpId); std::string rowNameK2 = "k2_" + UtilIntToStr(a) + "_" + UtilIntToStr(tpId); model->appendRow(rowK1, -m_infinity, bigM, rowNameK1); model->appendRow(rowK2, -bigM, m_infinity, rowNameK2); } } //--- create max. no. of switchings-constraint CoinPackedVector row; for(a = 0; a < numArcs; a++){ colIndex = col_zStartIndex + tpId * numArcs + a; if(arcs[a].acline == 1) { //only for arcs with voltage constraints row.insert(colIndex, 1.0); } } //model->appendRow(row, numACArcs-numSwitchings, numACArcs, std::string("sum{1-z}<=k")); std::string rowNameSumK = "sumk_" + UtilIntToStr(tpId); model->appendRow(row, numACArcs-numSwitchings, numACArcs, rowNameSumK); //--- //--- create a list of the "active" columns (those related //--- to this commmodity) all other columns are fixed to 0 //--- UtilFillN(model->colLB, numCols, 0.0); UtilFillN(model->colUB, numCols, 0.0); colIndex = 0; for(a = 0; a < numArcs; a++){ //set y-columns active //if(tpId == 0) { //colIndex = col_yStartIndex + a; // model->colLB[colIndex] = 0; // model->colUB[colIndex] = 1; // model->activeColumns.push_back(colIndex); //cout << "" << colIndex << ", " ; //} //set z-columns active colIndex = col_zStartIndex + tpId * numArcs + a; model->colLB[colIndex] = 0; //1 - arcs[a].switchable; //if arc not switchable then fix z=1 model->colUB[colIndex] = 1; model->activeColumns.push_back(colIndex); //set x-columns active colIndex = col_xStartIndex + tpId * numArcs + a; double arcLB = min(0.0, arcs[a].lb * ts[arcs[a].tscap].values[tpId]); //!!**** double arcUB = arcs[a].ub * ts[arcs[a].tscap].values[tpId]; model->colLB[colIndex] = arcLB; model->colUB[colIndex] = arcUB; model->activeColumns.push_back(colIndex); } //set theta-columns active for(i = 0; i < numNodes; i++){ colIndex = col_thetaStartIndex + tpId * numNodes + i; model->colLB[colIndex] = -m_infinity; model->colUB[colIndex] = m_infinity; model->activeColumns.push_back(colIndex); } //--- //--- set the indices of the integer variables of model //--- UtilIotaN(model->integerVars, col_xStartIndex, col_yStartIndex); ////Display problem //cout << "find: \nActive cols: "; //std::vector<int>::const_iterator it; //for(it = model->getActiveColumns().begin(); it < model->getActiveColumns().end(); it++){ //cout << *it << " "; //} //cout << "\ns.t.\n"; //for(j = 0; j < model->getNumRows(); j++){ //cout << model->rowNames[j] << " : \t\t"; //cout << model->rowLB[j] << " \t <= \t" ; //for (i = 0; i < model->getNumCols(); i++){ ////cout << "numCols=" << model->getNumCols() << endl; //if(model->getMatrix()->getCoefficient(j,i) != 0) { ////cout << "i" << i << " "; //cout << " " << model->M->getCoefficient(j,i) << " (" << i << ") + "; ////cout << model->getColNames()[i] ; //} //else {cout << "" ;} //} //cout << " \t <= \t " << model->rowUB[j] << endl ; // //} UtilPrintFuncEnd(m_osLog, m_classTag, "createModelRelax()", m_appParam.LogLevel, 2); }
//===========================================================================// void SDPUC_DecompApp::createModelCore(DecompConstraintSet * model){ //--- //--- 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 //--- 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 int numRows = numArcs * numTimeperiods; int col_yStartIndex = 0; int col_zStartIndex = numArcs*(1+numTimeperiods); int col_xStartIndex = numArcs * (1 + 2*numTimeperiods); int col_thetaStartIndex = numArcs*(1 + 3*numTimeperiods) ; SDPUC_Instance::arc * arcs = m_instance.m_arcs; UtilPrintFuncBegin(m_osLog, m_classTag, "createModelCore()", m_appParam.LogLevel, 2); //--- //--- create space for the model matrix (row-majored) //--- model->M = new CoinPackedMatrix(false, 0.0, 0.0); if(!model->M) throw UtilExceptionMemory("createModelCore", "SDPUC_DecompApp"); model->M->setDimensions(0, numCols); model->reserve(numRows, numCols); //--- //--- create the rows and set the col/row bounds //--- UtilFillN(model->colLB, numCols, -m_infinity); UtilFillN(model->colUB, numCols, m_infinity); for(a = 0; a < numArcs; a++){ colIndex = a; //add y1-vars model->colLB[colIndex] = 0; model->colUB[colIndex] = 1; for(t = 0; t < numTimeperiods; t++){ int t_prev = 0; if(t == 0) { t_prev = numTimeperiods - 1; } else { t_prev = t - 1; } colIndex = a + t * numArcs + numArcs; //add y2-vars model->colLB[colIndex] = 0; model->colUB[colIndex] = 1; CoinPackedVector row1; // 0 <= y1[i,j] - z[i,j,t] for all (i,j) in A, t in T CoinPackedVector row2; // 0 <= y2[i,j,t] - z[i,j,t] + z[i,j,t-1] for all (i,j) in A, t in T CoinPackedVector rowFix_y1; //fix y1=1 CoinPackedVector y2upper1; // y2(t) <= z(t) : if off in t then we dont start-up CoinPackedVector y2upper2; // y2(t) <= 1-z(t-1) : if on in t-1 then dont start up in t //insert y1-var coefficient row1.insert(a, 1.0); rowFix_y1.insert(a, 1.0); //insert y2-var coefficient colIndex = t * numArcs + a + numArcs; row2.insert(colIndex, 1.0); y2upper1.insert(colIndex, -1.0); y2upper2.insert(colIndex, -1.0); //add z-vars colIndex = t * numArcs + a + col_zStartIndex; model->colLB[colIndex] = 0; model->colUB[colIndex] = 1; //insert z-var coefficient row1.insert(colIndex, -1.0); row2.insert(colIndex, -1.0); y2upper1.insert(colIndex, 1.0); colIndex = t_prev * numArcs + a + col_zStartIndex; row2.insert(colIndex, 1.0); y2upper2.insert(colIndex, -1.0); std::string rowName1_1 = "MP1_1_" + UtilIntToStr(a) + "_" + UtilIntToStr(t); std::string rowName1_2 = "MP1_2_" + UtilIntToStr(a) + "_" + UtilIntToStr(t); std::string rowName2_1 = "MP2_1_" + UtilIntToStr(a) + "_" + UtilIntToStr(t); std::string rowName2_2 = "MP2_2_" + UtilIntToStr(a) + "_" + UtilIntToStr(t); std::string rowNameFix = "fix_y1_" + UtilIntToStr(a) + "_" + UtilIntToStr(t); //TODO: any issue with range constraint model->appendRow(row1, 0.0, m_infinity, rowName1_1); //add MP1_constraints (arc investments) model->appendRow(row1, -m_infinity, 1.0, rowName1_2); //add MP1_constraints (arc investments) if(arcs[a].tail == 0) { //ONLY for supply arcs (!!) model->appendRow(row2, 0.0, m_infinity, rowName2_1); //add MP2_constraints (arc commitment) model->appendRow(row2, -m_infinity, 1.0, rowName2_2); //add MP2_constraints (arc commitment) } model->appendRow(rowFix_y1, 1.0, m_infinity, rowNameFix); //add fix y1 vars //model->appendRow(y2upper1, 0.0, m_infinity, std::string("y2-upperbound-1")); //add upperbounds on y2 //model->appendRow(y2upper2, -1.0, m_infinity, std::string("y2-upperbound-2")); //..to strengthen formulation } } //--- //--- create column names (helps with debugging) //--- //y-vars for(a = 0; a < numArcs; a++){ std::string colName = "y1(a" + UtilIntToStr(a) + "(" + UtilIntToStr(arcs[a].tail) + "," + UtilIntToStr(arcs[a].head) + "))"; model->colNames.push_back(colName); } for(t = 0; t < numTimeperiods; t++){ for(a = 0; a < numArcs; a++){ std::string colName = "y2(t" + UtilIntToStr(t) + ",a" + UtilIntToStr(a) + "(" + UtilIntToStr(arcs[a].tail) + "," + UtilIntToStr(arcs[a].head) + "))"; model->colNames.push_back(colName); } } //z-vars for(t = 0; t < numTimeperiods; t++){ for(a = 0; a < numArcs; a++){ std::string colName = "z(t" + UtilIntToStr(t) + ",a" + UtilIntToStr(a) + "(" + UtilIntToStr(arcs[a].tail) + "," + UtilIntToStr(arcs[a].head) + "))"; model->colNames.push_back(colName); } } //x-vars for(t = 0; t < numTimeperiods; t++){ for(a = 0; a < numArcs; a++){ std::string colName = "x(t" + UtilIntToStr(t) + ",a" + UtilIntToStr(a) + "(" + UtilIntToStr(arcs[a].tail) + "," + UtilIntToStr(arcs[a].head) + "))"; model->colNames.push_back(colName); } } //theta-vars for(t = 0; t < numTimeperiods; t++){ for(i = 0; i < numNodes; i++){ std::string colName = "theta(t" + UtilIntToStr(t) + ",n" + UtilIntToStr(i) + ")"; model->colNames.push_back(colName); } } //--- //--- create a list of the "active" columns (those related //--- to this commmodity) all other columns are fixed to 0 //--- UtilFillN(model->colLB, numCols, 0.0); UtilFillN(model->colUB, numCols, 0.0); colIndex = 0; for(a = 0; a < numArcs; a++){ //set y-columns active //model->colLB[colIndex] = 0; //model->colUB[colIndex] = 1; //model->activeColumns.push_back(colIndex); //set y-columns as master-only columns colIndex = col_yStartIndex + a; model->masterOnlyCols.push_back(colIndex); //y1-vars for(t = 0; t < numTimeperiods; t++){ colIndex = col_yStartIndex + t * numArcs + a + numArcs; model->masterOnlyCols.push_back(colIndex); //y2-vars } } if(m_appParam.LogLevel >= 3){ (*m_osLog) << "Master only columns:" << endl; UtilPrintVector(model->masterOnlyCols, m_osLog); if(model->getColNames().size() > 0) UtilPrintVector(model->masterOnlyCols, model->getColNames(), m_osLog); } //--- //--- set the indices of the integer variables of model //--- UtilIotaN(model->integerVars, col_xStartIndex, col_yStartIndex); UtilPrintFuncEnd(m_osLog, m_classTag, "createModelCore()", m_appParam.LogLevel, 2); //--- //--- display problem //--- //int j = 0; //cout << "find: \nActive cols: "; //std::vector<int>::const_iterator it; //for(it = model->getActiveColumns().begin(); it != model->getActiveColumns().end(); it++){ //cout << *it << " "; //} // //cout << "\ns.t.\n"; //for(j = 0; j < model->getNumRows(); j++){ //cout << model->rowNames[j] << " : \t\t"; //cout << model->rowLB[j] << " \t <= \t" ; //for (i = 0; i < model->getNumCols(); i++){ ////cout << "numCols=" << model->getNumCols() << endl; //if(model->getMatrix()->getCoefficient(j,i) != 0) { ////cout << "i" << i << " "; //cout << " " << model->M->getCoefficient(j,i) << " " ; //cout << model->getColNames()[i] ; //} //else {cout << "" ;} //} //cout << " \t <= \t " << model->rowUB[j] << endl ; // //} }
//===========================================================================// int SDPUC_Instance::readInstance(string & fileName, bool addDummyArcs){ ifstream is; int status = UtilOpenFile(is, fileName.c_str()); if(status) throw UtilException("Failed to read instance", "readInstance", "MCF_Instance"); double sumweight = 0; bool size_read = true; int arcs_read = 0; int nodes_read = 0; int ts_read = 0; int nt = 0; char line[1000]; char name[1000]; while(is.good()) { is.getline(line, 1000); if (is.gcount() >= 999) { cerr << "ERROR: Input file is incorrect. " << "A line more than 1000 characters is found." << endl; return 1; } switch (line[0]) { case 'p': if (sscanf(line, "p%s%i%i%i%i%i", name, &m_numNodes, &m_numArcs, &m_numSwitchings, &m_numTimeseries, &m_numTimeperiods) != 6) { cerr << "ERROR: Input file is incorrect. (p line)" << endl; return 1; } m_problemName = name; m_arcs = new arc[m_numArcs + (addDummyArcs ? 0 : 0)]; if(!m_arcs) throw UtilExceptionMemory("readInstance", "MCF_DecompApp"); m_nodes = new node[m_numNodes]; if(!m_nodes) throw UtilExceptionMemory("readInstance", "MCF_DecompApp"); m_timeseries = new timeseries[m_numTimeseries]; if(!m_timeseries) throw UtilExceptionMemory("readInstance", "MCF_DecompApp"); break; case 'c': break; case '#': break; case 'n': if (sscanf(line, "n%i%lf%i", &m_nodes[nodes_read].id, &m_nodes[nodes_read].demand, &m_nodes[nodes_read].tsdemand) != 3) { cerr << "ERROR: Input file is incorrect. (n line)" << endl; return 1; } ++nodes_read; break; case 'a': if (sscanf(line, "a%i%i%lf%lf%lf%lf%lf%lf%i%i%i%i", &m_arcs[arcs_read].tail, &m_arcs[arcs_read].head, &m_arcs[arcs_read].lb, &m_arcs[arcs_read].ub, &m_arcs[arcs_read].weight, &m_arcs[arcs_read].mcost, &m_arcs[arcs_read].fcost1, &m_arcs[arcs_read].fcost2, &m_arcs[arcs_read].tscap, &m_arcs[arcs_read].tscost, &m_arcs[arcs_read].acline, &m_arcs[arcs_read].switchable ) != 12) { cerr << "Input file is incorrect. (a line)" << endl; return 1; } sumweight += fabs(m_arcs[arcs_read].mcost); ++arcs_read; break; case 't': //cout << "ts_read=" << ts_read ; //cout << " numTimeperiods=" << m_numTimeperiods << endl; m_timeseries[ts_read].values = new double[m_numTimeperiods]; /* if (sscanf(line, "t%i%lf%lf%lf%lf", &m_timeseries[ts_read].id, &m_timeseries[ts_read].values[0], &m_timeseries[ts_read].values[1], &m_timeseries[ts_read].values[2], &m_timeseries[ts_read].values[3] ) != 5) { cerr << "ERROR: Input file is incorrect. (t line) << " << line << endl; return 1; }*/ nt = 0; char * pch; //printf ("Splitting string \"%s\" into tokens:\n",line); pch = strtok (line,"\t"); //stripping the initial 't' //printf ("%s ",pch); pch = strtok (NULL, "\t"); //timeseries id m_timeseries[ts_read].id = atoi(pch); //printf ("%s\n",pch); while (pch != NULL && nt < m_numTimeperiods) { pch = strtok (NULL, "\t"); m_timeseries[ts_read].values[nt] = atof(pch); //printf ("%s\n",pch); nt++; } ++ts_read; break; default: if (sscanf(line+1, "%s", name) <= 0) { cerr << "Input file is incorrect. (non-recognizable line)" << endl; return 1; } break; } } if (!size_read || arcs_read != m_numArcs || nodes_read != m_numNodes || ts_read != m_numTimeseries ) { cerr << "Input file is incorrect." << " size_read=" << size_read << " arcs_read=" << arcs_read << " nodes_read=" << nodes_read << " ts_read=" << ts_read << endl; return 1; } /*if (addDummyArcs) { for (int i = 0; i < m_numCommodities; ++i) { m_arcs[m_numArcs].tail = m_commodities[i].source; m_arcs[m_numArcs].head = m_commodities[i].sink; m_arcs[m_numArcs].lb = 0; m_arcs[m_numArcs].ub = m_commodities[i].demand; m_arcs[m_numArcs].weight = sumweight+1; ++m_numArcs; } }*/ is.close(); return 0; }