[SCIP] Implementing no-good cuts that cuts off feasible solutions

Gerald Gamrath gamrath at zib.de
Thu Oct 19 14:46:06 CEST 2023


Hi Matheus,

I think there are multiple options how to make this work.

First, if you want to store data at a node, you need to write a 
constraint handler and add constraints to the nodes. Please have a look 
at this FAQ about branch-and-price, where something similar is done: 
https://www.scipopt.org/doc/html/FAQ.php#pricerandnodedata

On the other hand, I would argue that there may be a more SCIP-ish way 
to achieve what you want. Recall that the CIP concept asks for a linear 
objective, but allows for (almost) arbitrary constraints. So my 
suggestion would be to introduce an auxiliary variable z, change your 
objective to c^T x + z and add a new constraint handler, which is 
responsible for ensuring that z = f(x). Now, this constraint handler can 
always check if that relation is fulfilled and, if not, reject a given 
solution candidate. When doing that, it could compute the correct z 
value and add this updated solution. I guess it should not add it 
directly to SCIP, since this would then result in some recursive call of 
the solution checking, but you can pass it to heur_trysol, which will 
then try to add that solution at the next-possible time. If you would be 
able to compute bounds on z based on the partial fixings of x columns at 
the current node, your constraint handler could even tighten the bound 
of z, leading to better dual bounds.

I hope this helps,

Gerald

On 10/19/23 14:08, Matheus Ota wrote:
> Hi Leon,
>
> Thanks for the email. You are right, this is another part of the 
> context that I forgot to mention: the function f(.) is non-negative. 
> Thus, if x' is an LP solution obtained at a node of the 
> branch-and-bound tree, \bar{x} is the best (integer) solution found so 
> far, and c^T x' >= c^T \bar{x} + f(\bar{x}), then we can prune the 
> node of x' (since c^T x' + f(x') >= c^T x').
>
> I don't want to count/enumerate all integer feasible points, what I'm 
> trying to do is to solve an optimization problem with a "strange" f(.) 
> function that I just know how to compute for integer points. After 
> thinking a while about how to do this in SCIP, I think my question 
> boils down to these two points:
> 1. Is it possible to update the best feasible solution "manually" 
> inside the callback? Or maybe just updating the primal bound value.
> 2. Alternatively, when branching, is it possible for me to create some 
> type of "node data"? If so, I guess I can create a flag for the nodes 
> that correspond to a single feasible point. I think this may be 
> possible, but I don't know where to look for an example. I have a 
> custom branching rule already, so maybe when creating the child nodes, 
> I can flag some nodes as "special", and then when checking feasibility 
> in the callback, I know that "special" nodes actually correspond to a 
> single feasible solution.
>
> Thanks again for your attention,
> Matheus
>
> Em qui., 19 de out. de 2023 às 02:10, Leon Eifler <eifler at zib.de> 
> escreveu:
>
>     Hi Matheus,
>
>     I am a bit confused: Wouldn't the pruning of nodes using the
>     objective value of \bar{x} in your case be invalid since you have
>     that nonlinear part to consider? Is adding f to the model and
>     solving a MINLP not an option for you?
>
>     In any case, I wanted to mention that SCIP already contains a
>     feature to count/enumerate all integer-feasible solutions:
>     https://www.scipopt.org/doc/html/COUNTER.php#COLLECTALLFEASEBLES
>
>     I hope this helps,
>
>     Leon
>
>     Am 10/18/2023 um 8:42 PM schrieb Matheus Ota:
>>     Sorry, there is a problem in the way I phrased the question. The
>>     objective value of solution \bar{x} is not given by just c^T
>>     \bar{x}, but by c^T \bar{x} + f(\bar{x}), where f is some
>>     non-linear function that I know how to compute whenever \bar{x}
>>     is feasible. So if solving the LP relaxation returns an integer
>>     feasible point \bar{x}, it does not necessarily mean that \bar{x}
>>     is optimal (because of the f(.) function). This f() function
>>     creates the need to enumerate with the no-good cuts.
>>
>>     Em qua., 18 de out. de 2023 às 14:32, Matheus Ota
>>     <matheusota at gmail.com> escreveu:
>>
>>         Dear SCIP Team,
>>
>>         I want to implement a no-good cut (that cuts off a single
>>         integer point of the feasible region) but I don't know how to
>>         proceed. Suppose that I want to solve the following problem:
>>         (P)     min cx
>>                   s.t.  Ax <= b
>>                          x binary
>>
>>         Suppose that \bar{x} is feasible for (P), then I can cut off
>>         just \bar{x} by using the "no-good cut"
>>         \sum_{i : \bar{x}_i = 0} x_i + \sum_{i : \bar{x}_i = 1} (1 -
>>         x_i) >= 1.
>>
>>         Note that I'm not requesting the no-good cut to be feasible
>>         for (P). This is because I want to essentially use SCIP to
>>         enumerate the solutions. I want to do the following process:
>>         1. Get a feasible solution \bar{x} to (P).
>>         2. Compare \bar{x} with the best feasible solution found so
>>         far, and update the best solution found if \bar{x} is better
>>         than the current one.
>>         3. Remove \bar{x} with a no-good cut.
>>
>>         Since I'm always removing a feasible point, in the end of the
>>         branch-and-bound, it should return that the problem is
>>         infeasible. However, I don't want to simply "discard"
>>         \bar{x}. I want to use the objective value of \bar{x} to
>>         possibly prune more nodes of the branch-and-bound tree. Do
>>         you have any suggestions on how to implement this?
>>
>>         The first idea that came to my mind was to branch whenever I
>>         find a feasible solution \bar{x}. Then in the left branch
>>         node I only have { \bar{x} } as the feasible region and in
>>         the right branch node I add the no-good cut that cuts off
>>         \bar{x}. The problem with this approach is that, if I'm on
>>         the left branch node, once I get a solution \bar{x} in the
>>         CONSCHECK method, I don't know how to differentiate if this
>>         is the first time that I've found \bar{x} (in which case I
>>         should branch) or if this is the second time that I've found
>>         it (in which case I'm on the left branch node, and I should
>>         just return that the solution is feasible). Also, I'm not
>>         totally sure that this is the "correct" approach to use.
>>
>>         Sorry for the long email, and any help is appreciated.
>>
>>         Best,
>>         Matheus
>>
>>
>>     _______________________________________________
>>     Scip mailing list
>>     Scip at zib.de
>>     https://listserv.zib.de/mailman/listinfo/scip
>     _______________________________________________
>     Scip mailing list
>     Scip at zib.de
>     https://listserv.zib.de/mailman/listinfo/scip
>
>
> _______________________________________________
> Scip mailing list
> Scip at zib.de
> https://listserv.zib.de/mailman/listinfo/scip
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listserv.zib.de/pipermail/scip/attachments/20231019/84b7e3bd/attachment.html>


More information about the Scip mailing list