在C++中使用SCIP求解器

本文介绍了如何在C/C++工程中使用SCIP求解器,并展示了在Python中通过PySCIPOpt调用的实例。重点讲解了基本线性问题求解接口、目标函数修改、模型信息打印和非线性问题处理。还提醒了关于binary变量约束的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SCIP求解器本身就是用C/C++开发的,对于C/C++提供了灵活的调用接口。即使是在python中调用,也是通过cython等语言实现了这些接口的封装,使其更符合python语言特点。比如pyscipopt.

可以通过下面的网址阅读源码,在写C++代码的时候,可以用作参考:

PySCIPOpt: PySCIPOpt

一、C/C++工程的搭建

有三个条件,需要保证:

1. 环境变量下加入了安装目录下的bin路径,也就是在cmd下敲入scip后,能够进入scip环境。

2. 能够找到头文件路径。

3. 所在环境能够找到libscip.lib,这个文件在安装目录的lib路径下面:

对于第2、3两条,可以将安装路径下的include目录和libscip.lib拷贝出来,放到自己的工程下面,然后加载到工程中。

比如,在工程中新建lib文件夹,将libscip.lib放到里面,新建public文件夹,将include放到里面,下面是用CMake加载这两部分的方式:

cmake_minimum_required (VERSION 3.0)
project(CmakeTest)

include_directories(
        public
        public/include  # 这是scip的头文件
    )
    
    add_executable(runTests
        scipTest.cpp
    )
    
find_library(scip_static NAMES scip PATHS "lib/") # 这是找到libscip.lib
target_link_libraries(runTests scip_static)

这样,需要加载的头文件和库文件就被加载到工程中了。 可以在scipTest.cpp中调用scip接口了。

其实在安装目录下的lib文件夹中提供了cmake文件夹,可以利用它来实现,可能更加官方。

二、常用的接口介绍

 1. 这些都是基本线性问题求解所需的接口:

通过一段代码最能说明问题,

#include <iostream>
#include <scip/scipdefplugins.h>


//目标函数: 2x+3y
//con 2x+3y >= 7
int main(void) {
    // creates and initializes SCIP data structures
    SCIP * _scip;
    SCIPcreate(&_scip);

    // include default plugins
    SCIPincludeDefaultPlugins(_scip);

    // creates empty problem and initializes all solving data structures
    SCIPcreateProbBasic(_scip, "test");

    //sets objective sense of problem
    SCIPsetObjsense(_scip, SCIP_OBJSENSE_MINIMIZE);

    // changes the value of an existing SCIP_Real parameter
    SCIPsetRealParam(_scip, "limits/gap", 0.00001);
    SCIPsetRealParam(_scip, "limits/time", 10);

    //--添加变量
    SCIP_VAR *xVar = nullptr;
    SCIPcreateVarBasic(_scip, &xVar, "_x", 0, SCIPinfinity(_scip), 2.0, SCIP_VARTYPE_INTEGER);
    SCIPaddVar(_scip, xVar);

    SCIP_VAR *yVar = nullptr;
    SCIPcreateVarBasic(_scip, &yVar, "_y", 0, SCIPinfinity(_scip), 3.0, SCIP_VARTYPE_INTEGER);
    SCIPaddVar(_scip, yVar);

    //--添加约束
    SCIP_CONS* zCons;
    SCIPcreateConsBasicLinear(_scip, &zCons, "z_cons", 0, NULL, NULL, 7,  SCIPinfinity(_scip));
    SCIPaddCoefLinear(_scip, zCons, xVar, 2);
    SCIPaddCoefLinear(_scip, zCons, yVar, 3);
    SCIPaddCons(_scip, zCons);

    SCIPsolve(_scip);

    //--取最优解
    SCIP_Real x_value = SCIPgetSolVal(_scip, SCIPgetBestSol(_scip), xVar);
    SCIP_Real y_value = SCIPgetSolVal(_scip, SCIPgetBestSol(_scip), yVar);

    //--释放资源
    SCIPreleaseVar(_scip, &xVar);
    SCIPreleaseVar(_scip, &yVar);

    SCIPreleaseCons(_scip, &zCons);
    
    SCIPfree(&_scip);

    std::cout << "x_value: " << x_value << std::endl;
    std::cout << "y_value: " << y_value << std::endl;

    return 0;
}

需要注意的是,通常设置目标函数的方式在添加变量的过程就完成了,因为设置参数的接口中就存在目标函数系数这一项。如果目标函数中没有这个变量,则设置成0即可。

2. 修改目标函数中变量参数的函数

但是有时候为了使流程更加符合一个常规的求解流程,常常将设置目标函数单独拿出来。这就需要在设置参数的时候,将对应变量在目标函数的参数全部设置成0,而在后面统一修改。通过下面的接口就可以实现。

SCIPchgVarObj(_scip, var, 1);

 3. 模型的信息打印方法

另外介绍一个调试常用的接口,这个接口可以将模型的信息打印到test.lp的文件里面,你可以在其中看到你设置的变量,约束条件,目标函数的系数等信息。

SCIPwriteLP(_scip, "D:/test.lp");

根据8.0官方接口修改文档:

- calling SCIPwriteLP() is now possible in Solved Stage

- SCIPwrite{LP,MIP} may no longer be called after solving, since the LP data structures may not be valid

4. 模型信息打印方法2

 还有一个对于调试很好用的接口:

SCIPwriteOrigProblem(_scip, path, "cip", FALSE);

可以将变量,约束条件等保存到文件中。调用时放到SCIPsolve接口之前,更具体用法可以参照官方文档。

输出的样例如下:

STATISTICS
  Problem name     : spring
  Variables        : 18 (11 binary, 1 integer, 0 implicit integer, 6 continuous)
  Constraints      : 0 initial, 9 maximal
OBJECTIVE
  Sense            : minimize
VARIABLES
  [binary] <wire1>: obj=0, original bounds=[0,1]
  [binary] <wire2>: obj=0, original bounds=[0,1]
  [binary] <wire3>: obj=0, original bounds=[0,1]
  [binary] <wire4>: obj=0, original bounds=[0,1]
  [binary] <wire5>: obj=0, original bounds=[0,1]
  [binary] <wire6>: obj=0, original bounds=[0,1]
  [binary] <wire7>: obj=0, original bounds=[0,1]
  [binary] <wire8>: obj=0, original bounds=[0,1]
  [binary] <wire9>: obj=0, original bounds=[0,1]
  [binary] <wire10>: obj=0, original bounds=[0,1]
  [binary] <wire11>: obj=0, original bounds=[0,1]
  [integer] <ncoils>: obj=0, original bounds=[0,+inf]
  [continuous] <volume>: obj=1, original bounds=[0,+inf]
  [continuous] <wirediam>: obj=0, original b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值