Example(IloEnv env) : nblocks(0), model(env), vars(env), ranges(env) { // Model data. // fixed[] is the fixed cost for opening a facility, // cost[i,j] is the cost for serving customer i from facility j. static double const fixed[] = { 2.0, 3.0, 3.0 }; static double const cost[] = { 2.0, 3.0, 4.0, 5.0, 7.0, 4.0, 3.0, 1.0, 2.0, 6.0, 5.0, 4.0, 2.0, 1.0, 3.0 }; #define NFACTORY ((CPXDIM)(sizeof(fixed) / sizeof(fixed[0]))) #define NCUSTOMER ((CPXDIM)((sizeof(cost) / sizeof(cost[0])) / NFACTORY)) nblocks = NCUSTOMER; IloExpr obj(env); // Create integer y variables. IloNumVarArray y(env); for (IloInt f = 0; f < NFACTORY; ++f) { std::stringstream s; s << "y" << f; IloIntVar v(env, 0, 1, s.str().c_str()); obj += fixed[f] * v; objMap[v] = fixed[f]; y.add(v); blockMap.insert(BlockMap::value_type(v, -1)); intersectMap.insert(IntersectMap::value_type(v, RowSet())); } // Create continuous x variables. IloNumVarArray x(env); for (IloInt f = 0; f < NFACTORY; ++f) { for (IloInt c = 0; c < NCUSTOMER; ++c) { std::stringstream s; s << "x" << f << "#" << c; IloNumVar v(env, 0.0, IloInfinity, s.str().c_str()); obj += v * cost[f * NCUSTOMER + c]; objMap[v] = cost[f * NCUSTOMER + c]; x.add(v); blockMap.insert(BlockMap::value_type(v, c)); intersectMap.insert(IntersectMap::value_type(v, RowSet())); } } vars.add(y); vars.add(x); model.add(vars); // Add objective function. model.add(IloMinimize(env, obj, "obj")); objSense = IloObjective::Minimize; obj.end(); // Satisfy each customer's demand. for (IloInt c = 0; c < NCUSTOMER; ++c) { std::stringstream s; s << "c1_" << c; IloRange r(env, 1.0, IloInfinity, s.str().c_str()); IloExpr lhs(env); for (IloInt f = 0; f < NFACTORY; ++f) { lhs += x[f * NCUSTOMER + c]; intersectMap[x[f * NCUSTOMER + c]].insert(r); } r.setExpr(lhs); ranges.add(r); lhs.end(); } // A factory must be open if we service from it. for (IloInt c = 0; c < NCUSTOMER; ++c) { for (IloInt f = 0; f < NFACTORY; ++f) { std::stringstream s; s << "c2_" << c << "#" << f; IloRange r(env, 0.0, IloInfinity, s.str().c_str()); intersectMap[x[f * NCUSTOMER + c]].insert(r); intersectMap[y[f]].insert(r); r.setExpr(-x[f * NCUSTOMER + c] + y[f]); ranges.add(r); } } // Capacity constraint. IloRange r(env, -IloInfinity, NFACTORY - 1, "c3"); IloExpr lhs(env); for (IloInt f = 0; f < NFACTORY; ++f) { lhs += y[f]; intersectMap[y[f]].insert(r); } r.setExpr(lhs); ranges.add(r); lhs.end(); model.add(ranges); #undef NFACTORY #undef NCUSTOMER }
bool SimplifyControlFlowGraphPass::_mergeExitBlocks(ir::IRKernel& k) { typedef std::unordered_map<ir::ControlFlowGraph::iterator, ir::ControlFlowGraph::instruction_iterator> BlockMap; report(" Merging exit blocks..."); BlockMap exitBlocks; // Find all blocks with exit instructions for(ir::ControlFlowGraph::iterator block = k.cfg()->begin(); block != k.cfg()->end(); ++block) { for(ir::ControlFlowGraph::instruction_iterator instruction = block->instructions.begin(); instruction != block->instructions.end(); ++instruction) { ir::PTXInstruction& ptx = static_cast<ir::PTXInstruction&>(**instruction); if(ptx.isExit() && ptx.opcode != ir::PTXInstruction::Trap) { // There should be an edge to the exit block assertM(block->find_out_edge(k.cfg()->get_exit_block()) != block->out_edges.end(), "No edge from " << block->label() << " to exit node."); exitBlocks.insert(std::make_pair(block, instruction)); break; } } } // If there is only one/zero blocks, then don't change anything if(exitBlocks.size() < 2) { if(exitBlocks.size() == 1) { ir::PTXInstruction& ptx = static_cast<ir::PTXInstruction&>(**exitBlocks.begin()->second); if(k.function()) { ptx.opcode = ir::PTXInstruction::Ret; } else { ptx.opcode = ir::PTXInstruction::Exit; } } return false; } // Otherwise... // 1) create a new exit block ir::ControlFlowGraph::iterator newExit = k.cfg()->insert_block( ir::BasicBlock(k.cfg()->newId())); ir::BasicBlock::EdgePointerVector deletedEdges = k.cfg()->get_exit_block()->in_edges; // 1a) Create edges targetting the new block for(ir::ControlFlowGraph::edge_pointer_iterator edge = deletedEdges.begin(); edge != deletedEdges.end(); ++edge) { k.cfg()->insert_edge(ir::Edge((*edge)->head, newExit, (*edge)->type)); k.cfg()->remove_edge(*edge); } k.cfg()->insert_edge(ir::Edge(newExit, k.cfg()->get_exit_block(), ir::Edge::FallThrough)); // 2) Delete the instructions from their blocks for(BlockMap::iterator block = exitBlocks.begin(); block != exitBlocks.end(); ++block) { report(" merging block " << block->first->label()); // 2a) Insert a branch from blocks with branch edges ir::ControlFlowGraph::edge_pointer_iterator edge = newExit->find_in_edge(block->first); if((*edge)->type == ir::Edge::Branch) { ir::PTXInstruction* newBranch = new ir::PTXInstruction( ir::PTXInstruction::Bra, ir::PTXOperand(newExit->label())); newBranch->uni = true; block->first->instructions.push_back(newBranch); } delete *block->second; block->first->instructions.erase(block->second); } // 3 Add an appropriate exit instruction to the new exit block if(k.function()) { newExit->instructions.push_back( new ir::PTXInstruction(ir::PTXInstruction::Ret)); } else { newExit->instructions.push_back( new ir::PTXInstruction(ir::PTXInstruction::Exit)); } return true; }