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

Background

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

CPLEX,也就是IBM ILOG CPLEX Optimization Studio
官方网站有正式版本,收费
在这里插入图片描述
但是!但是IBM有一个Global University Programs
通过学校分配的邮箱可以在IBM注册会员并免费使用其软件
在这里插入图片描述
注册完后,就可以免费使用了(第一次体会到了学校邮箱的作用)
在这里插入图片描述
在这里插入图片描述
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

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

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

VS的C# .Net中调用CPLEX

  1. 项目目录 →引用 →右键 → 添加引用
    在这里插入图片描述

  2. 浏览 → 浏览 →导入ILOG.CPLEX.dll和ILOG.Concert.dll →确定在这里插入图片描述

  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求的总是最优解,衡量性能的为运行时间

FilenameOPTCPLEXTime(ms)
scp41.txt429429164
scp410.txt51451484
scp42.txt51251281
scp43.txt51651676
scp44.txt49449499
scp45.txt51251275
scp46.txt56056098
scp47.txt43043078
scp48.txt492492107
scp49.txt641641114
scp51.txt253253268
scp510.txt265265154
scp52.txt302302227
scp53.txt226226147
scp54.txt242242181
scp55.txt211211166
scp56.txt213213166
scp57.txt293293184
scp58.txt288288172
scp59.txt279279146
scp61.txt138138436
scp62.txt146146673
scp63.txt145145135
scp64.txt131131112
scp65.txt161161337
scpa1.txt253253895
scpa2.txt252252725
scpa3.txt232232711
scpa4.txt234234428
scpa5.txt236236398
scpb1.txt6969901
scpb2.txt76761429
scpb3.txt80801066
scpb4.txt79791676
scpb5.txt7272880
scpc1.txt227227847
scpc2.txt2192191451
scpc3.txt2432431706
scpc4.txt219219683
scpc5.txt215215878
scpd1.txt60601602
scpd2.txt66662220
scpd3.txt72722148
scpd4.txt62622067
scpd5.txt6161884
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值