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

2024-01-03 17:21:53

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

环境配置

? ? ? ? 首先开一个空项目

????????提前准备好gurobi的文件夹,最主要的是里面的两个文件夹的地址,vs2022与gurobi11.00是相对应的【据说版本对应不上是用不了的,但是我没有试过】gurobi11.0对应vs2017~vs2023

两个文件夹地址分别为

C:\gurobi1100\win64\include

C:\gurobi1100\win64\lib

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

选择【属性】

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

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

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

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

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

C:\gurobi1100\win64\lib

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

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

????????gurobi_c++mdd2017.lib

????????gurobi110.lib

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

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

函数测试

/* 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;
}

运行结果如下图所示:

Gurobi介绍

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

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

导入头文件

????????环境配置之后,可以导入

#include<gurobi_c++.h>

错误报告

????????不知道为什么,所有代码都是在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里面

创建环境

????????先展示一下官方代码

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

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

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

就可以了。

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

创建模型

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

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");

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

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(可选)新变量的名称。
返回值新的变量对象。

变量类型

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

1.0

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

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

GRBModel::addVars()

一次添加多个变量?

向模型添加约束

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

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(可选)新约束的名称。
返回值新的约束对象。

设置优化目标

// 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);

优化模型

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

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

// 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;

????????我们还可以查询模型上的?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问题会再开一个新帖子,这个帖子会根据后续我的学习再进行补充

文章来源:https://blog.csdn.net/qq_58249029/article/details/135299601
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。