使用定价器在根节点播出后,如何在 SCIP 中使用约束处理程序添加分隔符?

How to add separators using constraint handlers in SCIP after airing at the root node using a pricer?

我最初尝试实现一个分支和价格算法,并且我在实现它方面取得了很大成功。我实施了一个定价器插件,一切似乎都正常。但我想通过添加一些削减来加强这个模型。而不是通常的分支削减价格方案,我只想在根节点添加削减(在所有列都添加到根节点之后,在分支开始并添加更多列之前),而不是在分支开始后进一步削减(至少这是目前的计划)。

我实现了一个基本的约束处理程序,目前它做的不多,但有一些占位符来检查是否正确调用了适当的函数。我从 TSP 源代码中复制了大部分内容。为了简洁起见,我删除了广泛的评论和文档

ConshdlrSCO.hpp如下

#ifndef __SCOCONSHDLRSCO_HPP__
#define __SCOCONSHDLRSCO_HPP__

#include "objscip/objscip.h"

namespace SCO
{
class ConshdlrSCO : public scip::ObjConshdlr
{
public:
   ConshdlrSCO(SCIP* scip)
      : ObjConshdlr(scip, "SCO", "SCO OR constraints",
         1000000, -2000000, -2000000, 1, -1, 1, 0,
         FALSE, FALSE, TRUE, SCIP_PROPTIMING_BEFORELP, SCIP_PRESOLTIMING_FAST)
    {}

   virtual ~ConshdlrSCO(){}

   virtual SCIP_DECL_CONSDELETE(scip_delete);

   virtual SCIP_DECL_CONSTRANS(scip_trans);

   virtual SCIP_DECL_CONSSEPALP(scip_sepalp);

   virtual SCIP_DECL_CONSSEPASOL(scip_sepasol);

   virtual SCIP_DECL_CONSENFOLP(scip_enfolp);

   virtual SCIP_DECL_CONSENFOPS(scip_enfops);

   virtual SCIP_DECL_CONSCHECK(scip_check);

   virtual SCIP_DECL_CONSPROP(scip_prop);

   virtual SCIP_DECL_CONSLOCK(scip_lock);

   virtual SCIP_DECL_CONSDELVARS(scip_delvars);

   virtual SCIP_DECL_CONSPRINT(scip_print);

   virtual SCIP_DECL_CONSHDLRISCLONEABLE(iscloneable)
   {
      return true;
   }

   virtual SCIP_DECL_CONSHDLRCLONE(scip::ObjProbCloneable* clone); /*lint !e665*/

   virtual SCIP_DECL_CONSCOPY(scip_copy);
}; 
SCIP_RETCODE SCIPcreateConsSCO(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
   const char*           name,               /**< name of constraint */
   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP? */
   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing? */
   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing? */
   SCIP_Bool             check,              /**< should the constraint be checked for feasibility? */
   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing? */
   SCIP_Bool             local,              /**< is constraint only valid locally? */
   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)? */
   SCIP_Bool             dynamic,            /**< is constraint dynamic? */
   SCIP_Bool             removable           /**< should the constraint be removed from the LP due to aging or cleanup? */
   );
}

#endif

ConshdlrSCO.cpp文件如下

#include <cassert>
#include <string>
#include <iostream>
#include "ConshdlrSCO.hpp"

#include "objscip/objscip.h"
#include "scip/cons_linear.h"


/* checks whether proposed solution contains a valid SCO OR in the graph */
static
SCIP_Bool find_SCO_OR(
   SCIP*              scip,               /**< SCIP data structure */
   SCIP_SOL*          sol                 /**< proposed solution */
   )
{  
    return false;
}

/* separates SCO  cuts */
static
SCIP_RETCODE sepaSCO(
   SCIP*              scip,               /**< SCIP data structure */
   SCIP_CONSHDLR*     conshdlr,           /**< the constraint handler itself */
   SCIP_CONS**        conss,              /**< array of constraints to process */
   int                nconss,             /**< number of constraints to process */
   int                nusefulconss,       /**< number of useful (non-obsolete) constraints to process */
   SCIP_SOL*          sol,                /**< primal solution that should be separated */
   SCIP_RESULT*       result              /**< pointer to store the result of the separation call */
   )
{
   std::cout << "sepaSCO seems to work!" << "\n";
   return SCIP_OKAY;
} 


SCIP_DECL_CONSDELETE(SCO::ConshdlrSCO::scip_delete)
{
   return SCIP_OKAY;
}


SCIP_DECL_CONSTRANS(SCO::ConshdlrSCO::scip_trans)
{

    std::cout << "scip_trans has started working!" << "\n";

    /* create target constraint */
    SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, nullptr,
          SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
          SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),  SCIPconsIsLocal(sourcecons),
          SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
          SCIPconsIsStickingAtNode(sourcecons)) );

   std::cout << "scip_trans has finished working!" << "\n";
   return SCIP_OKAY;
}


SCIP_DECL_CONSSEPALP(SCO::ConshdlrSCO::scip_sepalp)
{
   std::cout << "SCIP_sepalp is working till here!" << "\n";
   SCIP_CALL( sepaSCO(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
   return SCIP_OKAY;
}


SCIP_DECL_CONSSEPASOL(SCO::ConshdlrSCO::scip_sepasol)
{
   return SCIP_OKAY;
}


SCIP_DECL_CONSENFOLP(SCO::ConshdlrSCO::scip_enfolp)
{
   return SCIP_OKAY;
}

SCIP_DECL_CONSENFOPS(SCO::ConshdlrSCO::scip_enfops)
{
   return SCIP_OKAY;
} 


SCIP_DECL_CONSCHECK(SCO::ConshdlrSCO::scip_check)
{
   std::cout << "SCIp_check_ works till here!" << "\n";
   return SCIP_OKAY;
} 


SCIP_DECL_CONSPROP(SCO::ConshdlrSCO::scip_prop)
{
    return SCIP_OKAY;
} 


SCIP_DECL_CONSLOCK(SCO::ConshdlrSCO::scip_lock)
{
   return SCIP_OKAY;
} 


SCIP_DECL_CONSDELVARS(SCO::ConshdlrSCO::scip_delvars)
{
   return SCIP_OKAY;
} 


SCIP_DECL_CONSPRINT(SCO::ConshdlrSCO::scip_print)
{
   return SCIP_OKAY;
} 

SCIP_DECL_CONSHDLRCLONE(scip::ObjProbCloneable* SCO::ConshdlrSCO::clone) 
{
   *valid = true;
   return new ConshdlrSCO(scip);
}


SCIP_DECL_CONSCOPY(SCO::ConshdlrSCO::scip_copy)
{
   return SCIP_OKAY;
} 

SCIP_RETCODE SCO::SCIPcreateConsSCO(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
   const char*           name,               /**< name of constraint */
   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP? */
   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing? */
   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing? */
   SCIP_Bool             check,              /**< should the constraint be checked for feasibility? */
   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing? */
   SCIP_Bool             local,              /**< is constraint only valid locally? */
   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)? */
   SCIP_Bool             dynamic,            /**< is constraint dynamic? */
   SCIP_Bool             removable           /**< should the constraint be removed from the LP due to aging or cleanup? */
   )
{
    SCIP_CONSHDLR* conshdlr;

    /* create constraint */
    conshdlr = SCIPfindConshdlr(scip, "SCO");
      if( conshdlr == NULL )
      {
         SCIPerrorMessage("SCO constraint handler not found\n");
         return SCIP_PLUGINNOTFOUND;
      }

    auto consdata = nullptr;

    SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
            local, modifiable, dynamic, removable, FALSE) );

    std::cout << "SCIPcreateConsSCO is working!" << "\n";

   return SCIP_OKAY;
}

我像这样一个接一个地添加了定价器和约束处理程序

ObjPricerSCO* SCO_pricer_ptr = new ObjPricerSCO(scip, SCO_PRICER_NAME, instance, z_vars, ..., , env2);\
SCIP_CALL( SCIPincludeObjPricer(scip, SCO_pricer_ptr, true) );

/* activate pricer */
SCIP_CALL( SCIPactivatePricer(scip, SCIPfindPricer(scip, SCO_PRICER_NAME)) );

SCO::ConshdlrSCO* SCO_cons_hdlr_ptr = new SCO::ConshdlrSCO(scip);
SCIP_CALL( SCIPincludeObjConshdlr(scip, SCO_cons_hdlr_ptr, true) );

//Adding the OR cut
SCIP_CONS* cons;
SCIP_CALL( SCO::SCIPcreateConsSCO(scip, &cons, "OR_SCO_cut", FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE ) );
SCIP_CALL( SCIPaddCons(scip, cons) );
SCIP_CALL( SCIPreleaseCons(scip, &cons) );

我只想在获得根节点之后和分支开始之前添加切割。现在没有分支(我通过将所有变量更改为连续来禁用它,以便算法在根节点停止)

所以我的问题是:

1)如何在根节点求解后(根节点是通过使用价格器添加列获得的)和分支开始之前添加切割

我可能对术语和语言有点不准确。对此表示歉意。

您的程序并未尝试添加切割,它会检查第 16、20、31 行中的解决方案。第一个是对伪解的检查(没有约束所有变量都设置为它们的最佳边界),第二个是对 lp 解的检查,最后一个是原始 space 中的最终检查。 现在回答您的问题:

1) 我认为你的程序没有分离,因为它不需要。您的原始解决方案值立即等于对偶边界(在您完成定价后)。所以真的没有必要分开任何东西。

2) 出现警告是因为 .lp 对允许打印的内容有非常严格的限制。我不知道你的约束会是什么样子。如果它们是线性的,您只需在约束处理程序中创建线性约束,您就可以将它们打印在 .lp 文件中。否则,您可以实施 consPrint 回调并打印为 .cip 文件。