分支定价求解GAP问题

关于分支定价求解GAP问题的Java实现

没有找到可以参考的列生成的实现方式,自己实现了一下,分享出来,一起学习

  1. 关于列生成和分支定价的部分可以参考
    https://blog.csdn.net/u014090505/article/details/89019327
  2. 广义分配(GAP)问题描述和模型参考的文献
    高振, 唐立新, 汪定伟. 列生成解大规模NP-hard整数与组合优化问题[J]. 信息与控制, 2005, 32(z1):604-607.
  3. 程序用Java实现,调用CPLEX
  4. 代码如下:
    GAP_BP.java
import java.io.IOException;
import java.util.ArrayList;

import ilog.concert.IloException;
public class GAP_BP
{	
	public static double RC_EPS = 1.0e-6;
	public static int nMachine=5;
	public static int nJob=10;
	public static  double[] b;
	public static double[] capacity;
	public static double[][] consume;
	public static double[][] profit;
	static class PAIR
	{ 
		public int job_id; 
		public double profit_weight; 
		public PAIR(int id, double pw)
		{
			job_id = id;
			profit_weight = pw;
		}
	} 
	public static void main(String[] args) throws IloException, IOException 
	{
		long begintime =0;
		long endtime=0;
		long costTime=0;
		begintime = System.currentTimeMillis();			
		GAP_BP BP=new GAP_BP();
		ArrayList<ProblemNode> nodeQueue=new ArrayList<>();
		ProblemNode node=new ProblemNode();
		node.initNode();
		nodeQueue.add(node);
		double[] bestS = null;
		double bestObj=Double.MIN_VALUE;
		ProblemNode problem0=new ProblemNode();
		while(nodeQueue.size()>0)
		{			
			ProblemNode problem=nodeQueue.get(nodeQueue.size()-1);
			boolean next=false;
			while(true)
			{
				double[] s = null;
				if(problem.solve())
					s=problem.curSol;
				else
				{
					next=true;
					break;
				}
				double tempObj=problem.curObj;
				System.out.println("obj"+tempObj);
				if(isIntSol(s)&&tempObj>bestObj)
				{
					bestObj=tempObj;
					bestS=s.clone();
					System.out.println("bestOBj:  "+bestObj);
					problem.outPutBest();
					problem0=problem;
				}
				int[] newPattern=problem.findPattern_CPLEX_IP();
				if(newPattern!=null)
				{
					problem.addColumn(newPattern);
					System.out.println("cloumnNum:::"+problem.columns.size());
				}	
				else
					break;
			}
			if(next)//由于不可行跳出循环, 终止节点
			{	
				problem.solver.end();
				nodeQueue.remove(nodeQueue.size()-1);
				continue;
			}
			else //由于不可继续加列跳出循环
			{
				if(problem.curObj<=bestObj||isIntSol(problem.curSol))
				{
					problem.solver.end();
					nodeQueue.remove(nodeQueue.size()-1);
					continue;
				}	
				else
				{
					System.out.println("分支");
					//分支,加俩节点,删除当前节点
					@SuppressWarnings("unchecked")
					ArrayList<Integer> fixedVars=(ArrayList<Integer>) problem.fixedVars.clone();
					double min=0.5;
					int index=0;
					for(int i=0;i<problem.curSol.length;i++)
					{
						double m=Math.rint(problem.curSol[i]);
						if(Math.abs(m-problem.curSol[i])>0)
						{
							index=i;
							break;
						}
					}
					System.out.println("index::  "+index+"                     var::  "+problem.curSol[index]);
					fixedVars.set(index, 0);
					ProblemNode node1=new ProblemNode(problem,fixedVars);
					
					fixedVars.set(index, 1);
					ProblemNode node2=new ProblemNode(problem,fixedVars);					
					problem.solver.end();
					nodeQueue.remove(nodeQueue.size()-1);
					nodeQueue.add(node1);
					nodeQueue.add(node2);
				}
			}
		}
		System.out.println("bestOBj:  "+bestObj);
		problem0.outPutBest();
		endtime=System.currentTimeMillis();
		costTime = (endtime - begintime);
		System.out.println("时间消耗:"+costTime/1000.0+"s");
	}
	public GAP_BP() throws IOException
	{
		String datafile = "./src/data5063.dat";
		readData(datafile);
		nMachine = capacity.length;
		nJob = consume[0].length;
	}
	public static void readData(String fileName)throws IOException
	{
		 InputDataReader reader = new InputDataReader(fileName);
		 try 
		 {
			b = reader.readDoubleArray();
			capacity = reader.readDoubleArray();
			consume  = reader.readDoubleArrayArray();
			profit   = reader.readDoubleArrayArray();
		 } 
		catch (InputDataReader.InputDataReaderException exc ) 
		{
			System.err.println(exc);
		}	
	}
	public static boolean isIntSol(double[] sol)
	{
		for(int i=0;i<sol.length;i++)
		{
			if((int)sol[i]!=sol[i])
				return false;
		}
		return true;
	}
}

ProblemNode.java

import java.io.IOException;
import java.util.ArrayList;
import ilog.concert.IloColumn;
import ilog.concert.IloException;
import ilog.concert.IloNumExpr;
import ilog.concert.IloNumVar;
import ilog.concert.IloNumVarType;
import ilog.concert.IloObjective;
import ilog.concert.IloRange;
import ilog.cplex.IloCplex;

public class ProblemNode 
{
	public IloRange[]  Fill;
	public IloNumVarArray patterns;
	public IloObjective totalProfit;
	public IloCplex solver; 
	public double[] curSol;
	public double curObj;
	public ArrayList<int[]> columns;
	public ArrayList<Integer> objs;
	public ArrayList<Integer> fixedVars;
	public ProblemNode()
	{
	}
	@SuppressWarnings("unchecked")
	public ProblemNode(ProblemNode node,ArrayList<Integer> fixedVars) throws IloException
	{
		this.fixedVars=(ArrayList<Integer>) fixedVars.clone();
	    this.objs=(ArrayList<Integer>) node.objs.clone();
		solver = new IloCplex(); 
		totalProfit = solver.addMaximize();//目标函数	   
	    Fill = new IloRange[GAP_BP.b.length];
        for (int f = 0; f < GAP_BP.b.length; f++) 
           Fill[f] = solver.addRange(GAP_BP.b[f],1);
        patterns = new IloNumVarArray();
        columns =new ArrayList<>();
        for(int i=0;i<node.columns.size();i++)
        {
        	addColumn(node.columns.get(i), node.objs.get(i),this.fixedVars.get(i));
        }
        solver.setOut(null);
	}
	public void initNode() throws IloException, IOException
	{
		solver = new IloCplex(); 
		totalProfit = solver.addMaximize();//目标函数	   
	    Fill = new IloRange[GAP_BP.b.length];
        for (int f = 0; f < GAP_BP.b.length; f++) 
           Fill[f] = solver.addRange(GAP_BP.b[f],1);
        
        ArrayList<int[]> sol = initSolution();
        patterns = new IloNumVarArray();
        fixedVars=new ArrayList<>();
        objs=new ArrayList<>();
        columns=new ArrayList<>();
		int[] column=new int[GAP_BP.nMachine+GAP_BP.nJob];
    	for(int j = 0; j < GAP_BP.nMachine; j++)
		{
			if(sol.get(j)[0]> 0)
			{	
				IloColumn pattern = solver.column(totalProfit,sol.get(j)[0]);
				objs.add(sol.get(j)[0]);
				column=new int[GAP_BP.nMachine+GAP_BP.nJob];
				for(int i = 0; i < GAP_BP.nJob; i++)
				{
					int value=sol.get(j)[i+2];
					pattern=pattern.and(solver.column(Fill[i],value));
					column[i]=value;
				}
				for(int i = 0; i < GAP_BP.nMachine; i++)
				{
					int value=0;
					if(j==i) 
						value=1;
					pattern=pattern.and(solver.column(Fill[GAP_BP.nJob+i],value));
					column[GAP_BP.nJob + i] = value;
				}
				fixedVars.add(-1);
				patterns.add(solver.numVar(pattern,0,1));
				columns.add(column);
			}
		}
		solver.setOut(null);
	}
	public boolean solve() throws IloException
	{
		if(!solver.solve())
			return false;
		curSol=new double[patterns.getSize()];
		for (int  j = 0; j < patterns.getSize(); j++) 
			curSol[j]=solver.getValue(patterns.getElement(j));
		curObj=solver.getObjValue();
		return true;
	}
	public void addColumn(int[] column,int profit,int fixed) throws IloException
	{
		   IloColumn pattern = solver.column(totalProfit,profit);
		   for(int i=0;i<column.length;i++)
			   pattern=pattern.and(solver.column(Fill[i],column[i]));
		   if(fixed==-1)
       			patterns.add(solver.numVar(pattern,0,1));
       	   else
       			patterns.add(solver.numVar(pattern,fixed,fixed));
		   columns.add(column.clone());
	}
	public void addColumn(int[] newPattern) throws IloException
	{
			int cur_profit = 0;
			int[] column=new int[GAP_BP.nMachine+GAP_BP.nJob];
			 //生成的新的子问题的解,转化成一列column
            IloColumn pattern = solver.column(Fill[0],newPattern[1]);
            column[0] =newPattern[1];
            cur_profit += newPattern[1] * GAP_BP.profit[newPattern[0]][0];
			for(int i = 1; i < GAP_BP.nJob; i++)   //设置新的方案,同时计算该方案的收益
			{
				pattern = pattern.and(solver.column(Fill[i],newPattern[i + 1]));
				cur_profit += newPattern[i+1] * GAP_BP.profit[newPattern[0]][i];
				column[i] =newPattern[i + 1];
			}
			for(int i = 0; i < GAP_BP.nMachine; i++)
			{	
				int value=0;
				if(i==newPattern[0])
					value=1;
				pattern = pattern.and(solver.column(Fill[GAP_BP.nJob+i],value));
				column[GAP_BP.nJob+i] =value;
			}
			IloColumn pp = solver.column(totalProfit,cur_profit);
			pattern=pp.and(pattern);
			patterns.add(solver.numVar(pattern,0,1));//添加新列new parttern
			columns.add(column);
			fixedVars.add(-1);
			objs.add(cur_profit);
	}
	//输出最优解
	public void outPutBest()
	{
		System.out.println();
		for(int i=0;i<curSol.length;i++)
		{
			if(curSol[i]==1)
			{
				int j=0;
				for(j=GAP_BP.nJob;j<columns.get(i).length;j++)
				{
					if(columns.get(i)[j]==1)
						System.out.print("M"+(j-GAP_BP.nJob)+":");
				}
				for(j=0;j<GAP_BP.nJob;j++)
				{
					if(columns.get(i)[j]==1)
						System.out.printf("%4s",j);
				}
				System.out.println();
			}
		}
	}
	//生成新的列,求解子问题(背包问题),可以选择合适的方法求解
	public  int[]  findPattern_CPLEX_IP() throws IloException
	{
		double[] price=solver.getDuals(Fill);
		double maxProfit =-1;//tmpProfit = 0;
		int[] bestPattern=null; 
		double[]  profit_j;
		double[]  consume_j;
		for(int j = 0; j <GAP_BP.nMachine; j++)
		{	
			IloCplex patSolver=new IloCplex();	patSolver.setOut(null);   
			profit_j=new double[GAP_BP.nJob];
			consume_j=new double[GAP_BP.nJob];
			for(int i = 0; i < GAP_BP.nJob; i++)
			{
				profit_j[i]=GAP_BP.profit[j][i] - price[i];
				consume_j[i]=(GAP_BP.consume[j][i]);
			}
			IloNumVar[] x =  patSolver.numVarArray(GAP_BP.nJob, 0, 1, IloNumVarType.Int);			patSolver.addMaximize(patSolver.diff(patSolver.scalProd(x, profit_j), price[GAP_BP.nJob+j]));
			IloNumExpr expr=patSolver.linearIntExpr();
			for(int i=0;i<GAP_BP.nJob;i++)				expr=patSolver.sum(expr,patSolver.prod(consume_j[i], x[i]));
			patSolver.addLe(expr,GAP_BP.capacity[j]);
		  	patSolver.solve();	  
			if (patSolver.getObjValue()> maxProfit)
			{
				maxProfit = patSolver.getObjValue();
				bestPattern=new int[GAP_BP.nJob+1];
				bestPattern[0]=j;//第一个元素记录机器的编号
				for(int i = 0; i < GAP_BP.nJob; i++)
					bestPattern[i+1]=(int)patSolver.getValue(x[i]);
			}
			if(maxProfit<GAP_BP.RC_EPS)
				bestPattern=null;
			patSolver.end();
		}
		return bestPattern;
	} 
	public static ArrayList<int[]> initSolution()
	{
		ArrayList<int[]> solutions=new ArrayList<>();
		for(int i=0;i<GAP_BP.nMachine;i++)
			solutions.add(new int[GAP_BP.nJob+2]);//第0号元素记录累计收益,第1号元素记录累计消耗,其他元素为1表示对应的任务分给了该机器
		ArrayList<Integer> jobsID=new ArrayList<>();
		int job = -1, machine = -1;
		double max_pw = 0;  //   profit/weight,即单位消耗的收益	
		for(int i = 0; i <GAP_BP.nJob; i++)
			jobsID.add(i);		
		while(jobsID.size() > 0)
		{
			max_pw = 0;
			for(int i = 0; i < jobsID.size(); i++)
			{
				for(int j = 0; j < GAP_BP.nMachine; j++)
				{
					if(solutions.get(j)[1]+GAP_BP.consume[j][jobsID.get(i)] > GAP_BP.capacity[j]) 
						continue; //如果机器能力不满足则跳过该机器
					if(GAP_BP.profit[j][jobsID.get(i)] / (double)GAP_BP.consume[j][jobsID.get(i)] > max_pw)
					{
						max_pw = GAP_BP.profit[j][jobsID.get(i)] / (double)GAP_BP.consume[j][jobsID.get(i)];
						job = i;
						machine = j;
					}
				}
			}
			solutions.get(machine)[jobsID.get(job)+ 2] = 1;
			solutions.get(machine)[0] += GAP_BP.profit[machine][jobsID.get(job)];
			solutions.get(machine)[1] += GAP_BP.consume[machine][jobsID.get(job)];
			jobsID.remove(job);
		}	
		return solutions;
	}
}

读文件函数,CPLEX样例程序自带,InputDataReader.java

/* --------------------------------------------------------------------------
 * File: InputDataReader.java
 * Version 12.6  
 * --------------------------------------------------------------------------
 * Licensed Materials - Property of IBM
 * 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55 5655-Y21
 * Copyright IBM Corporation 2001, 2013. All Rights Reserved.
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with
 * IBM Corp.
 * --------------------------------------------------------------------------
 *
 * This is a helper class used by several examples to read input data files
 * containing arrays in the format [x1, x2, ..., x3].  Up to two-dimensional
 * arrays are supported.
 */

import java.io.*;

public class InputDataReader {
   public static class InputDataReaderException extends Exception {
      private static final long serialVersionUID = 1021L;
      InputDataReaderException(String file) {
         super("'" + file + "' contains bad data format");
      }
   }
   
   StreamTokenizer _tokenizer;
   Reader _reader;
   String _fileName;

   public InputDataReader(String fileName) throws IOException {
      _reader = new FileReader(fileName);
      _fileName = fileName;
    
      _tokenizer = new StreamTokenizer(_reader);
    
      // State the '"', '\'' as white spaces.
      _tokenizer.whitespaceChars('"', '"');
      _tokenizer.whitespaceChars('\'', '\'');
    
      // State the '[', ']' as normal characters.
      _tokenizer.ordinaryChar('[');
      _tokenizer.ordinaryChar(']');
      _tokenizer.ordinaryChar(',');
   }

   protected void finalize() throws Throwable {
      _reader.close();
   }

   double readDouble() throws InputDataReaderException,
                              IOException {
      int ntType = _tokenizer.nextToken();
      
      if ( ntType != StreamTokenizer.TT_NUMBER )
         throw new InputDataReaderException(_fileName);
      
      return _tokenizer.nval;
   }
     
   int readInt() throws InputDataReaderException,
                        IOException {
      int ntType = _tokenizer.nextToken();
    
      if ( ntType != StreamTokenizer.TT_NUMBER )
         throw new InputDataReaderException(_fileName);
      
      return (new Double(_tokenizer.nval)).intValue();
   }
   
   double[] readDoubleArray() throws InputDataReaderException,
                                     IOException {
      int ntType = _tokenizer.nextToken(); // Read the '['
      
      if ( ntType != '[' )
         throw new InputDataReaderException(_fileName);
      
      DoubleArray values = new DoubleArray();
      ntType = _tokenizer.nextToken();
      while (ntType == StreamTokenizer.TT_NUMBER) {
         values.add(_tokenizer.nval);
         ntType = _tokenizer.nextToken();
         
         if ( ntType == ',' ) {
            ntType = _tokenizer.nextToken();
         }
         else if ( ntType != ']' ) {
            throw new InputDataReaderException(_fileName);
         }
      }
      
      if ( ntType != ']' )
         throw new InputDataReaderException(_fileName);
    
      // Allocate and fill the array.
      double[] res = new double[values.getSize()];
      for (int i = 0; i < values.getSize(); i++) {
         res[i] = values.getElement(i);
      }
      
      return res;
   }

   double[][] readDoubleArrayArray() throws InputDataReaderException,
                                            IOException {
      int ntType = _tokenizer.nextToken(); // Read the '['
      
      if ( ntType != '[' )
         throw new InputDataReaderException(_fileName);
      
      DoubleArrayArray values = new DoubleArrayArray();
      ntType = _tokenizer.nextToken();
      
      while (ntType == '[') {
         _tokenizer.pushBack();
         
         values.add(readDoubleArray());
         
         ntType = _tokenizer.nextToken();
         if      ( ntType == ',' ) {
           ntType = _tokenizer.nextToken();
         }
         else if ( ntType != ']' ) {
           throw new InputDataReaderException(_fileName);
         }
      }
    
      if ( ntType != ']' )
         throw new InputDataReaderException(_fileName);
    
      // Allocate and fill the array.
      double[][] res = new double[values.getSize()][];
      for (int i = 0; i < values.getSize(); i++) { 
         res[i] = new double[values.getSize(i)];
         for (int j = 0; j < values.getSize(i); j++) { 
            res[i][j] = values.getElement(i,j);
         }
      }
      return res;
   }

   int[] readIntArray() throws InputDataReaderException,
                               IOException {
      int ntType = _tokenizer.nextToken(); // Read the '['
      
      if ( ntType != '[' )
         throw new InputDataReaderException(_fileName);
      
      IntArray values = new IntArray();
      ntType = _tokenizer.nextToken();
      while (ntType == StreamTokenizer.TT_NUMBER) {
         values.add(_tokenizer.nval);
         ntType = _tokenizer.nextToken();
         
         if      ( ntType == ',' ) {
            ntType = _tokenizer.nextToken();
         }
         else if ( ntType != ']' ) {
            throw new InputDataReaderException(_fileName);
         }
      }
      
      if ( ntType != ']' )
         throw new InputDataReaderException(_fileName);

      // Allocate and fill the array.
      int[] res = new int[values.getSize()];
      for (int i = 0; i < values.getSize(); i++) {
         res[i] = values.getElement(i);
      }
      return res;
   }

   int[][] readIntArrayArray() throws InputDataReaderException,
                                      IOException {
      int ntType = _tokenizer.nextToken(); // Read the '['
      
      if ( ntType != '[' )
         throw new InputDataReaderException(_fileName);
      
      IntArrayArray values = new IntArrayArray();
      ntType = _tokenizer.nextToken();
      
      while (ntType == '[') {
         _tokenizer.pushBack();
         
         values.add(readIntArray());
         
         ntType = _tokenizer.nextToken();
         if      ( ntType == ',' ) {
            ntType = _tokenizer.nextToken();
         }
         else if ( ntType != ']' ) {
            throw new InputDataReaderException(_fileName);
         }
      }
    
      if ( ntType != ']' )
         throw new InputDataReaderException(_fileName);
    
      // Allocate and fill the array.
      int[][] res = new int[values.getSize()][];
      for (int i = 0; i < values.getSize(); i++) {
         res[i] = new int[values.getSize(i)];
         for (int j = 0; j < values.getSize(i); j++) {
            res[i][j] = values.getElement(i,j);
         }
      }    
      return res;
   }

   private class DoubleArray {
      int      _num   = 0;
      double[] _array = new double[32];

      final void add(double dval) {
         if ( _num >= _array.length ) {
            double[] array = new double[2 * _array.length];
            System.arraycopy(_array, 0, array, 0, _num);
            _array = array;
         }
         _array[_num++] = dval;
      }

      final double getElement(int i) { return _array[i]; }
      final int    getSize()         { return _num; }
   }

   private class DoubleArrayArray {
      int        _num   = 0;
      double[][] _array = new double[32][];

      final void add(double[] dray) {

         if ( _num >= _array.length ) {
            double[][] array = new double[2 * _array.length][];
            for (int i = 0; i < _num; i++) {
               array[i] = _array[i];
            }
            _array = array;
         }
         _array[_num] = new double[dray.length];
         System.arraycopy(dray, 0, _array[_num], 0, dray.length);
         _num++;
      }

      final double getElement(int i, int j) { return _array[i][j]; }
      final int    getSize()                { return _num; }
      final int    getSize(int i)           { return _array[i].length; }
   }


   private class IntArray {
      int   _num   = 0;
      int[] _array = new int[32];

      final void add(double ival) {
         if ( _num >= _array.length ) {
            int[] array = new int[2 * _array.length];
            System.arraycopy(_array, 0, array, 0, _num);
            _array = array;
         }
         _array[_num++] = (int)Math.round(ival);
      }

      final int getElement(int i) { return _array[i]; }
      final int getSize()         { return _num; }
   }

   private class IntArrayArray {
      int     _num   = 0;
      int[][] _array = new int[32][];

      final void add(int[] iray) {

         if ( _num >= _array.length ) {
            int[][] array = new int[2 * _array.length][];
            for (int i = 0; i < _num; i++) {
               array[i] = _array[i];
            }
            _array = array;
         }
         _array[_num] = new int[iray.length];
         System.arraycopy(iray, 0, _array[_num], 0, iray.length);
         _num++;
      }

      final int getElement(int i, int j) { return _array[i][j]; }
      final int getSize()                { return _num; }
      final int getSize(int i)           { return _array[i].length; }
   }
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值