Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码

Background

上一节大纲
Hololens Anchor 自动布局(一)—— 背景、问题以及可行性分析
讲到,求解ILP的一个比较好的求解器就是CPLEX。

CPLEX,也就是IBM ILOG CPLEX Optimization Studio
官方网站有正式版本,收费
Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码_第1张图片
但是!但是IBM有一个Global University Programs。
通过学校分配的邮箱可以在IBM注册会员并免费使用其软件
Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码_第2张图片
注册完后,就可以免费使用了(第一次体会到了学校邮箱的作用)
Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码_第3张图片
Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码_第4张图片
Click Download,然后选择对应的操作系统就行了
(总感觉IBM的按钮按起来很带感,也可能是free的原因)

Windows下配置CPLEX

在Windows下的CPLEX库是DLL文件,命名方式为:cplexXXX.dll ,
其中 XXX 代表的当前的版本号。在Windows下可以通过多种方式定位cplexXXX.dll

  1. 添加环境变量PATH
  2. 在Visual Studio中链接cplexXXX.dll

添加CPLEX DLL到PATH

  1. 开始 - 控制面板
  2. 系统
  3. 高级系统设置
  4. 环境变量
  5. 修改环境变量:
Name : PATH
Value : %PATH%;你的CPLEX路径\CPLEXXXX\bin\X86_win32
  1. 重启VS或者Windows中的其他应用

在Visual Studio的项目里链接CPLEX DLL

Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码_第5张图片

在Visual Studio .Net项目中配置和调用CPLEX

由于是WPF程序,我直接把该文件夹下的文件拷贝到了我的项目目录下。在项目中

VS的C# .Net中调用CPLEX

  1. 项目目录 →引用 →右键 → 添加引用
    Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码_第6张图片

  2. 浏览 → 浏览 →导入ILOG.CPLEX.dll和ILOG.Concert.dll →确定Hololens Anchor 自动布局(二)—— Windows下CPLEX的配置,在VS2015中的调用以及解决SCP问题的代码_第7张图片

  3. User’s manual for .Net (pdf下载)

帮助文档下载

CPLEX 的 官方API手册下载

针对.Net用户的 官方API下载

在下求解集合覆盖问题的代码

数据结构 DataStruct.cs

using ILOG.Concert;
using ILOG.CPLEX;
using System.Collections;

namespace mynamespace
{
    #region patch190120 by bxy

    class BaoSCP
    {
        public List<Anchor> anchors;

        //该问题和集合覆盖问题等价,锚点相当于子集,模型相当于集合里的元素
        //一个锚点可以覆盖多个模型,相当于,一个字集可以包含多个元素
        
        public int x_length; //锚点的个数
        public int v_length; //模型的个数

        public int[] x_weight; //每个空间锚的权重 (设为1,即每多放置一个空间锚,总成本+1)
        public int[] x_min; //下限为0 代表不使用该时间锚
        public int[] x_max; //上限为1 代表    使用该时间锚
        public int[] v_min; //每个模型的下界为1,即至少有一个空间锚覆盖它
        public int[] v_max; //每个模型的上界无界限(官方示例程序设为9999),即所有空间锚都可以覆盖它
        public int[][] a;//第i个锚点是否覆盖第j个模型,1为是,0为否

        private bool byColumn = true;
        NumVarType varType = NumVarType.Int; //整数规划

        public bool Valid_Result;
        public int[] result;

        public BaoSCP()
        {
            anchors = new List<Anchor>();
        }

        public void Add(Anchor anchor)
        {
            this.anchors.Add(new Anchor(anchor.loc, anchor.models));
        }

        public void Standard()
        {
            UpdateLength();

            x_weight = new int[x_length];
            x_min = new int[x_length];
            x_max = new int[x_length];

            for(int i=0;i<x_length;++i)
            {
                x_weight[i] = 1;
                x_min[i] = 0;
                x_max[i] = 1;
            }

            v_min = new int[v_length];
            v_max = new int[v_length];

            for(int i=0;i<v_length;++i)
            {
                v_min[i] = 1;
                v_max[i] = 9999;
            }


            a = new int[v_length][];
            for(int i=0;i<v_length;++i)
            {
                a[i] = new int[x_length];
                for (int j = 0; j < x_length; ++j)
                    a[i][j] = 0;
            }

            int len;
            for(int i=0;i<x_length;++i)
            {
                len = anchors[i].models.Count();
                for(int j=0;j<len;++j)
                {
                    a[i][anchors[i].models[j]] = 1;
                }
            }

        }


        public void Start()
        {
            try
            {
                Valid_Result = false;

                Cplex cplex = new Cplex();

                INumVar[] Result = new INumVar[x_length];

                if (byColumn)
                    BuildModelByColumn(cplex, Result, varType);
                else
                    BuildModelByRow(cplex, Result, varType);

                if (cplex.Solve())
                {
                    int[] res = new int[x_length];
                   
                    for (int i = 0; i < x_length; i++)
                        res[i] = int.Parse(cplex.GetValue(Result[i]).ToString());
                    

                    Output(cplex.GetStatus(), cplex.ObjValue, res);
                }

                cplex.End();

            }
            catch (ILOG.Concert.Exception ex)
            {
                System.Console.WriteLine("Concert Error: " + ex);
            }
            catch (System.IO.IOException ex)
            {
                System.Console.WriteLine("IO Error: " + ex);
            }
        }

        public void Output(Cplex.Status status, double cost, int[] Result)
        {
            this.result = new int[x_length];
            System.Console.WriteLine();
            System.Console.WriteLine("Solution status = " +status);
            System.Console.WriteLine();
            System.Console.WriteLine(" cost = " + cost);
            for (int i = 0; i < x_length; i++)
            {
                System.Console.WriteLine(" Buy"
                + i + " = " + Result[i]);
                this.result[i] = Result[i];
            }
            System.Console.WriteLine();
            
            Valid_Result = true;

        }

        private void BuildModelByRow(IModeler model, INumVar[] Result, NumVarType type)
        {
            for (int j = 0; j < x_length; j++)
            {
                Result[j] = model.NumVar(x_min[j], x_max[j], type); //每个锚点要么放,要么不放
            }
            model.AddMinimize(model.ScalProd(x_weight, Result)); //目标是最小化锚点的价值(也就是数量)

            for (int i = 0; i < v_length; i++)
            {
                model.AddRange(v_min[i], model.ScalProd(a[i], Result), v_max[i]); //添加约束
            }

        }

        private void BuildModelByColumn(IMPModeler model, INumVar[] Result, NumVarType type)
        {

            IObjective cost = model.AddMinimize();
            IRange[] constraint = new IRange[v_length];

            for (int i = 0; i < v_length; i++)
            {
                constraint[i] = model.AddRange(v_min[i], v_max[i]);
            }

            for (int j = 0; j < x_length; j++)
            {
                Column col = model.Column(cost,x_weight[j]);
                for (int i = 0; i < v_length; i++)
                {
                    col = col.And(model.Column(constraint[i], a[i][j]));
                }
                Result[j] = model.NumVar(col, x_min[j], x_max[j], type);
            }


        }
      

        private void UpdateLength()
        {
            v_length = 0;
            x_length = anchors.Count();
            for(int i=0;i<x_length;++i)
            {
                int len = anchors[i].models.Count();
                for(int j=0;j<len;++j)
                {
                    if(anchors[i].models[j]>v_length)
                    {
                        v_length = anchors[i].models[j];
                    }
                }
            }
            v_length++;
        }
    }

    #endregion
}

Main Program 主程序窗口 MainWindows.xaml.cs

  #region patch190120 by bxy
 		List<BaoPath> paths; //这是和外界连接的数据结构,可忽略
        BaoSCP scp = new BaoSCP();

        void ILP()
        {
            int[] result = new int[paths.Count()];
            ConvertModelsToSCP(paths);
            if(SCPBasedOnCplex(ref result))
                //some operations based on "result" array
                ;
        }

        void ConvertModelsToSCP(List<BaoPath> paths)
        {
            for (int i = 0; i < maxn; ++i)
                for (int j = 0; j < maxn; ++j)
                {
                    pixels[i, j].value = 0;
                    pixels[i, j].id = "";

                }


            int radius = 75;//这个值要 equals 现实中的3米

            int length = WallAndModelList.Count();

            #region loop
            for(int i=0;i<length;++i)
            {
                BaoModel bm = WallAndModelList[i];
                PointD center = new PointD(bm.x, bm.y);

                List<BaoSide> PointVis = new List<BaoSide>();
                GetsVisibleRegion(center.X, center.Y, false, ref PointVis);

                for (int ii = BInt(center.Y - radius, true); ii <= BInt(center.Y, false); ++ii)
                {
                    double j_tmp = Math.Sqrt(radius * radius - (center.Y - ii) * (center.Y - ii));
                    for (int jj = BInt(center.X - j_tmp, true); jj <= BInt(center.X + j_tmp, false); ++jj)
                    {
                        if (IsPointInPolygon(jj, ii, PointVis))
                        {
                            pixels[jj, ii].Add(WallAndModelList[i].value, WallAndModelList[i].id); //可能有问题
                        }

                    }
                }
                for (int ii = BInt(center.Y + 1, false); ii <= BInt(center.Y + radius, false); ++ii)
                {
                    double j_tmp = Math.Sqrt(radius * radius - (ii - center.Y) * (ii - center.Y));
                    for (int jj = BInt(center.X - j_tmp, true); jj <= BInt(center.X + j_tmp, false); ++jj)
                    {
                        if (IsPointInPolygon(jj, ii, PointVis))
                        {
                            pixels[jj, ii].Add(WallAndModelList[i].value, WallAndModelList[i].id); //可能有问题
                        }
                    }
                }

            }
            #endregion

            int bias = 31;

            double last_value = -1;
            string last_string = "null";
            // int fi = -1;
            // int fj = -1;

            Anchor anchor;
            List<int> models = new List<int>();

            for (int i = 0; i < maxn; ++i)
                for (int j = 0; j < maxn; ++j)
                {
                    if (pixels[i, j].value!=0&&(!pixels[i,j].id.Equals(last_string)||pixels[i,j].value!=last_value))
                    {
                        String[] ss = pixels[i, j].id.Split(',');
                        int len = ss.Count();
                        for (int k = 0; k < len; ++k)
                        {
                            if (ss[k].Count() != 0)
                                models.Add(int.Parse(ss[i].ToString())+bias);
                        }
                        anchor = new Anchor(new PointD(i, j), models);
                        scp.Add(anchor);
                    }
                }


        }

        bool SCPBasedOnCplex(ref int[] result)
        {
            int length = scp.x_length;
            scp.Standard();
            scp.Start();
            if(scp.Valid_Result)
            {
                for (int i = 0; i < length; ++i)
                    result[i] = scp.result[i];
                return true;
            }
            return false;
        }

        #endregion

测试结果

测试数据采自 J.E.Beasley 的 OR-Library
在下网络上搜到的关于CSP的Paper,都使用此数据进行测试
Instances For Set Covering (OR-Library)

实验结果如下:
由于是确实性算法,所以CPLEX求的总是最优解,衡量性能的为运行时间

Filename OPT CPLEX Time(ms)
scp41.txt 429 429 164
scp410.txt 514 514 84
scp42.txt 512 512 81
scp43.txt 516 516 76
scp44.txt 494 494 99
scp45.txt 512 512 75
scp46.txt 560 560 98
scp47.txt 430 430 78
scp48.txt 492 492 107
scp49.txt 641 641 114
scp51.txt 253 253 268
scp510.txt 265 265 154
scp52.txt 302 302 227
scp53.txt 226 226 147
scp54.txt 242 242 181
scp55.txt 211 211 166
scp56.txt 213 213 166
scp57.txt 293 293 184
scp58.txt 288 288 172
scp59.txt 279 279 146
scp61.txt 138 138 436
scp62.txt 146 146 673
scp63.txt 145 145 135
scp64.txt 131 131 112
scp65.txt 161 161 337
scpa1.txt 253 253 895
scpa2.txt 252 252 725
scpa3.txt 232 232 711
scpa4.txt 234 234 428
scpa5.txt 236 236 398
scpb1.txt 69 69 901
scpb2.txt 76 76 1429
scpb3.txt 80 80 1066
scpb4.txt 79 79 1676
scpb5.txt 72 72 880
scpc1.txt 227 227 847
scpc2.txt 219 219 1451
scpc3.txt 243 243 1706
scpc4.txt 219 219 683
scpc5.txt 215 215 878
scpd1.txt 60 60 1602
scpd2.txt 66 66 2220
scpd3.txt 72 72 2148
scpd4.txt 62 62 2067
scpd5.txt 61 61 884

你可能感兴趣的:(CPLEX,VS,整数规划,ILP,Windows,科研,C#,Hololens,NP)