用C++调用Gurobi的基操教学(后续倾向求解VRP问题)

        最近要用到Gurobi,而我自己不经常用python,但是在晚上几乎找不到除了操作手册之外的攻略,这对于我一个重度依赖CSDN的人来说简直是大灾难,所以在这里边学边记录,教学相长,欢迎评论区纠错

1.环境配置

        首先开一个空项目用C++调用Gurobi的基操教学(后续倾向求解VRP问题)_第1张图片

        提前准备好gurobi的文件夹,最主要的是里面的两个文件夹的地址,vs2022与gurobi11.00是相对应的【据说版本对应不上是用不了的,但是我没有试过】gurobi11.0对应vs2017~vs2023用C++调用Gurobi的基操教学(后续倾向求解VRP问题)_第2张图片

两个文件夹地址分别为

C:\gurobi1100\win64\include

C:\gurobi1100\win64\lib

1.1配置C/C++外部包含目录

用C++调用Gurobi的基操教学(后续倾向求解VRP问题)_第3张图片

选择【属性】

用C++调用Gurobi的基操教学(后续倾向求解VRP问题)_第4张图片

【VC/C++】 → 【外部包含目录V】 →<编辑>

将地址C:\gurobi1100\win64\include添加进去

同时,需要确保【C/C++】的子菜单项【预编译头】设置为【不使用预编译头】。

1.2配置链接器的附加库目录和附加依赖项

【链接器】 → 【常规】 → 【附加库目录】下,添加下文件路径:

C:\gurobi1100\win64\lib

用C++调用Gurobi的基操教学(后续倾向求解VRP问题)_第5张图片

        接下来在gurobi文件夹中,进入C:\gurobi1100\win64\lib

        具体如下图所示,选择红框中的两个文件,其名称分别是:

        gurobi_c++mdd2017.lib

        gurobi110.lib

用C++调用Gurobi的基操教学(后续倾向求解VRP问题)_第6张图片

        应在【链接器】 → 【输入】 → 【附加依赖项】下添加这两个文件,注意,用英文分号;隔开。

        最后点击确定,至此配置完成,接下来用官网公布的一段代码进行测试,如果运行成功就证明配置OK啦

1.3函数测试

/* Copyright 2023, Gurobi Optimization, LLC */

/* This example formulates and solves the following simple MIP model:

     maximize    x +   y + 2 z
     subject to  x + 2 y + 3 z <= 4
                 x +   y       >= 1
                 x, y, z binary
*/

#include "gurobi_c++.h"
using namespace std;

int
main(int   argc,
     char *argv[])
{
  try {

    // Create an environment
    GRBEnv env = GRBEnv(true);
    env.set("LogFile", "mip1.log");
    env.start();

    // Create an empty model
    GRBModel model = GRBModel(env);

    // Create variables
    GRBVar x = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "x");
    GRBVar y = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "y");
    GRBVar z = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "z");

    // Set objective: maximize x + y + 2 z
    model.setObjective(x + y + 2 * z, GRB_MAXIMIZE);

    // Add constraint: x + 2 y + 3 z <= 4
    model.addConstr(x + 2 * y + 3 * z <= 4, "c0");

    // Add constraint: x + y >= 1
    model.addConstr(x + y >= 1, "c1");

    // Optimize model
    model.optimize();

    cout << x.get(GRB_StringAttr_VarName) << " "
         << x.get(GRB_DoubleAttr_X) << endl;
    cout << y.get(GRB_StringAttr_VarName) << " "
         << y.get(GRB_DoubleAttr_X) << endl;
    cout << z.get(GRB_StringAttr_VarName) << " "
         << z.get(GRB_DoubleAttr_X) << endl;

    cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << endl;

  } catch(GRBException e) {
    cout << "Error code = " << e.getErrorCode() << endl;
    cout << e.getMessage() << endl;
  } catch(...) {
    cout << "Exception during optimization" << endl;
  }

  return 0;
}

运行结果如下图所示:

用C++调用Gurobi的基操教学(后续倾向求解VRP问题)_第7张图片

2.Gurobi介绍

        直接跳过,因为我相信但凡来查找如何使用的朋友,一定都有自己的使用目的且在一定程度上了解gurobi

        而我每次点开同类帖子大段的文字描写环境配置和介绍,一问到底怎么写,就说不出来了

3.导入头文件

        环境配置之后,可以导入

#include

4.错误报告

        不知道为什么,所有代码都是在try里面写的,有固定格式的感觉,但是由于我c++学的也不好,没办法解释

int main()
{
    try 
    {
      // Formulate and solve model
    } 
    catch(GRBException e)
    {
      cout << "Error code = " << e.getErrorCode() << endl;
      cout << e.getMessage() << endl;
    } catch(...) 
    {
      cout << "Exception during optimization" << endl;
    }
}

        主要书写内容都在try里面

5.创建环境

        先展示一下官方代码

// Create an environment
GRBEnv env = GRBEnv(true);
env.set("LogFile", "mip1.log");
env.start();

        但实际上,经过翻阅各类信息,合理利用gpt与实验,我发现只用写

// 创建Gurobi环境
        GRBEnv env = GRBEnv();

就可以了。

        我目前还是不知道是为什么的。(不知道评论区有没有大佬可以帮我解答一下)

6.创建模型

        直接照抄模板,按顺序copy就可以了

GRBModel model = GRBModel(env);

7.向模型添加变量

先看示例

// Create variables
GRBVar x = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "x");
GRBVar y = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "y");
GRBVar z = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "z");

        变量是通过模型对象上的 GRBModel::addVar 方法添加的。

7.1 GRBModel::addVar()

addVar() 一次增加一个变量

GRBVar addVar (double lb, double ub, double obj, char type, string name="" )

参数 详解
lb 新变量的下限。
ub 新变量的上限。
obj 新变量的客观系数。
type 新变量的变量类型(GRB_CONTINUOUS、GRB_BINARY、GRB_INTEGER、GRB_SEMICONT 或 GRB_SEMIINT)。
names(可选) 新变量的名称。
返回值 新的变量对象。

7.1.1变量类型

变量类型 意义 用处 常规下限 上限
GRB_CONTINUOUS 连续型 0 INFINITY
GRB_BINARY 二进制 0-1整数规划模型 0.0

1.0

GRB_INTEGER 整数型
GRB_SEMICONT 半连续性
GRB_SEMIINT 半整数(?)

         关于变量类型上下限的部分,暂时留白,因为我也没有看懂,只是翻阅了一下代码发现常规都是这样的,肯定还需要根据自己的问题切实修改。

7.2 GRBModel::addVars()

一次添加多个变量?

8.向模型添加约束

// Add constraint: x + 2 y + 3 z <= 4
model.addConstr(x + 2 * y + 3 * z <= 4, "c0");

8.1 GRBModel::addConstr()

种类很多……我暂时没发现除了参数不同之外还有什么区别,也不知道怎么区分去使用

 GRBConstr     addConstr(const GRBLinExpr& lhsExpr,
                            char sense,
                            const GRBLinExpr& rhsExpr,
                            string name="" )

参数 详解
lhsExpr 新线性约束的左侧表达式。
sense 感知新的线性约束(GRB_LESS_EQUAL、GRB_EQUAL 或 GRB_GREATER_EQUAL)。
rhsExpr 新线性约束的右侧表达式。
names(可选) 新约束的名称。
返回值 新的约束对象。

9.设置优化目标

// Set objective: maximize x + y + 2 z
model.setObjective(x + y + 2 * z, GRB_MAXIMIZE);

        还有第二种表达方法,应该是面对累加∑等情况,可以和循环搭配使用

GRBLinExpr obj = 0.0;
obj += x;
obj += y;
obj += 2*z;
model.setObjective(obj, GRB_MAXIMIZE);

10.优化模型

        特别神奇的事情,只需要一行代码就可以搞定所有优化?

         这可能就是这个优化器的神奇之处吧

// Optimize model
model.optimize();

11.结果输出

cout << x.get(GRB_StringAttr_VarName) << " "
     << x.get(GRB_DoubleAttr_X) << endl;
cout << y.get(GRB_StringAttr_VarName) << " "
     << y.get(GRB_DoubleAttr_X) << endl;
cout << z.get(GRB_StringAttr_VarName) << " "
     << z.get(GRB_DoubleAttr_X) << endl;

        我们还可以查询模型上的 ObjVal 属性,以获取当前解决方案的目标值:

cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << endl;

题目概述

        经典VRP问题,多仓库多城市多车,找最短路径分配的VRP问题的代码。仓库开启需要花费100元,仓库关闭需要花费成本50元,持续运营在每一个回合需要耗费10元,车行驶一个单位长度需要花费10元,每辆车都必须从仓库出发,并且在完成配送任务后返回仓库,目标函数为最小花费。

现在已有参数以及目标函数及约束条件

1.在代码里添加所有参数作为变量?(doing)

2.定义集合?

感想随记

12.29夜晚开坑,在实验室里一时冲动就开了帖子,结果晚上快11点的时候被关门大爷赶了出去

12.30写着写着发现自己关于LP的知识全部还给老师了,今天去图书馆突击看一下……不然连符号都看不懂了,目前这个文章写得太草率了,主要是因为后续关于如何解决VRP问题,我遇到了比较多的问题正在解决,后续VRP问题会再开一个新帖子,这个帖子会根据后续我的学习再进行补充

你可能感兴趣的:(C++调用Gurobi,c++,开发语言)