Scippy

    SCIP

    Solving Constraint Integer Programs

    scip_validation.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file scip_validation.c
    26 * @ingroup OTHER_CFILES
    27 * @brief public methods for validation
    28 * @author Tobias Achterberg
    29 * @author Timo Berthold
    30 * @author Gerald Gamrath
    31 * @author Leona Gottwald
    32 * @author Stefan Heinz
    33 * @author Gregor Hendel
    34 * @author Thorsten Koch
    35 * @author Alexander Martin
    36 * @author Marc Pfetsch
    37 * @author Michael Winkler
    38 * @author Kati Wolter
    39 *
    40 * @todo check all SCIP_STAGE_* switches, and include the new stages TRANSFORMED and INITSOLVE
    41 */
    42
    43/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    44
    45#include "scip/pub_message.h"
    46#include "scip/pub_misc.h"
    47#include "scip/pub_sol.h"
    48#include "scip/scip_general.h"
    49#include "scip/scip_message.h"
    50#include "scip/scip_numerics.h"
    51#include "scip/scip_param.h"
    52#include "scip/scip_prob.h"
    53#include "scip/scip_sol.h"
    56#include "scip/scip_exact.h"
    57#include "scip/rational.h"
    58
    59/** validate the result of the solve
    60 *
    61 * the validation includes
    62 *
    63 * - checking the feasibility of the incumbent solution in the original problem (using SCIPcheckSolOrig())
    64 *
    65 * - checking if the objective bounds computed by SCIP agree with external primal and dual reference bounds.
    66 *
    67 * All external reference bounds the original problem space and the original objective sense.
    68 *
    69 * For infeasible problems, +/-SCIPinfinity() should be passed as reference bounds depending on the objective sense
    70 * of the original problem.
    71 */
    73 SCIP* scip, /**< SCIP data structure */
    74 SCIP_Real primalreference, /**< external primal reference value for the problem, or SCIP_UNKNOWN */
    75 SCIP_Real dualreference, /**< external dual reference value for the problem, or SCIP_UNKNOWN */
    76 SCIP_Real reftol, /**< relative tolerance for acceptable violation of reference values */
    77 SCIP_Bool quiet, /**< TRUE if no status line should be printed */
    78 SCIP_Bool* feasible, /**< pointer to store if the best solution is feasible in the original problem,
    79 * or NULL */
    80 SCIP_Bool* primalboundcheck, /**< pointer to store if the primal bound respects the given dual reference
    81 * value, or NULL */
    82 SCIP_Bool* dualboundcheck /**< pointer to store if the dual bound respects the given primal reference
    83 * value, or NULL */
    84 )
    85{
    86 SCIP_Bool localfeasible;
    87 SCIP_Bool localprimalboundcheck;
    88 SCIP_Bool localdualboundcheck;
    89 SCIP_Real primviol;
    90 SCIP_Real dualviol;
    91 assert(scip != NULL);
    92
    93 /* if no problem exists, there is no need for validation */
    95 {
    96 if( feasible != NULL )
    97 *feasible = TRUE;
    98 if( primalboundcheck != NULL )
    99 *primalboundcheck = TRUE;
    100 if( dualboundcheck != NULL )
    101 *dualboundcheck = TRUE;
    102
    103 return SCIP_OKAY;
    104 }
    105
    106 localfeasible = TRUE;
    107 localdualboundcheck = TRUE;
    108
    109 /* check the best solution for feasibility in the original problem */
    110 if( SCIPgetNSols(scip) > 0 )
    111 {
    112 SCIP_SOL* bestsol = SCIPgetBestSol(scip);
    113 SCIP_Real checkfeastolfac;
    114 SCIP_Real oldfeastol;
    115
    116 assert(bestsol != NULL);
    117
    118 /* scale feasibility tolerance by set->num_checkfeastolfac */
    119 oldfeastol = SCIPfeastol(scip);
    120 SCIP_CALL( SCIPgetRealParam(scip, "numerics/checkfeastolfac", &checkfeastolfac) );
    121 if( !SCIPisEQ(scip, checkfeastolfac, 1.0) )
    122 {
    123 SCIP_CALL( SCIPchgFeastol(scip, oldfeastol * checkfeastolfac) );
    124 }
    125
    126 SCIP_CALL( SCIPcheckSolOrig(scip, bestsol, &localfeasible, !quiet, TRUE) );
    127
    128 /* restore old feasibilty tolerance */
    129 if( !SCIPisEQ(scip, checkfeastolfac, 1.0) )
    130 {
    131 SCIP_CALL( SCIPchgFeastol(scip, oldfeastol) );
    132 }
    133 }
    134 else
    135 {
    136 localfeasible = TRUE;
    137 }
    138
    139 primviol = 0.0;
    140 dualviol = 0.0;
    141 /* check the primal and dual bounds computed by SCIP against the external reference values within reference tolerance */
    142 /* solution for an infeasible problem */
    144 || (SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE && SCIPisInfinity(scip, -dualreference))) )
    145 localprimalboundcheck = FALSE;
    146 else
    147 {
    148 /* check if reference primal bound is not better than the proven dual bound and, if SCIP claims to be optimal,
    149 * if the
    150 */
    153
    154 /* compute the relative violation between the primal bound and dual reference value, and vice versa */
    156 {
    157 if( dualreference != SCIP_UNKNOWN ) /*lint !e777 */
    158 primviol = SCIPrelDiff(dualreference, pb);
    159 if( primalreference != SCIP_UNKNOWN ) /*lint !e777 */
    160 dualviol = SCIPrelDiff(db, primalreference);
    161 }
    162 else
    163 {
    164 if( dualreference != SCIP_UNKNOWN ) /*lint !e777 */
    165 primviol = SCIPrelDiff(pb, dualreference);
    166
    167 if( primalreference != SCIP_UNKNOWN ) /*lint !e777 */
    168 dualviol = SCIPrelDiff(primalreference, db);
    169 }
    170 primviol = MAX(primviol, 0.0);
    171 dualviol = MAX(dualviol, 0.0);
    172
    173 localprimalboundcheck = EPSP(reftol, primviol);
    174 localdualboundcheck = EPSP(reftol, dualviol);
    175 }
    176
    177 if( !quiet )
    178 {
    179 SCIPinfoMessage(scip, NULL, "Validation : ");
    180 if( ! localfeasible )
    181 SCIPinfoMessage(scip, NULL, "Fail (infeasible)");
    182 else if( ! localprimalboundcheck )
    183 SCIPinfoMessage(scip, NULL, "Fail (primal bound)");
    184 else if( ! localdualboundcheck )
    185 SCIPinfoMessage(scip, NULL, "Fail (dual bound)");
    186 else
    187 SCIPinfoMessage(scip, NULL, "Success");
    188 SCIPinfoMessage(scip, NULL, "\n");
    189 SCIPinfoMessage(scip, NULL, " %-17s: %10u\n", "cons violation", !localfeasible); /*lint !e705*/
    190 SCIPinfoMessage(scip, NULL, " %-17s: %10.8g (reference: %16.9e)\n", "primal violation", primviol, dualreference);
    191 SCIPinfoMessage(scip, NULL, " %-17s: %10.8g (reference: %16.9e)\n", "dual violation", dualviol, primalreference);
    192 }
    193
    194 if( feasible != NULL )
    195 *feasible = localfeasible;
    196 if( primalboundcheck != NULL )
    197 *primalboundcheck = localprimalboundcheck;
    198 if( dualboundcheck != NULL )
    199 *dualboundcheck = localdualboundcheck;
    200
    201 return SCIP_OKAY;
    202}
    203
    204/** validate the result of an exact solve
    205 *
    206 * the validation includes
    207 *
    208 * - checking the feasibility of the incumbent solution in the original problem (using SCIPcheckSolOrig())
    209 *
    210 * - checking if the objective bounds computed by SCIP agree with external primal and dual reference bounds.
    211 *
    212 * All external reference bounds the original problem space and the original objective sense.
    213 *
    214 * For infeasible problems, +/-inf should be passed as reference bounds depending on the objective sense
    215 * of the original problem.
    216 */
    218 SCIP* scip, /**< SCIP data structure */
    219 SCIP_RATIONAL* primalreference, /**< external primal reference value for the problem, or SCIP_UNKNOWN */
    220 SCIP_RATIONAL* dualreference, /**< external dual reference value for the problem, or SCIP_UNKNOWN */
    221 SCIP_Bool quiet, /**< TRUE if no status line should be printed */
    222 SCIP_Bool* feasible, /**< pointer to store if the best solution is feasible in the original problem,
    223 * or NULL */
    224 SCIP_Bool* primalboundcheck, /**< pointer to store if the primal bound respects the given dual reference
    225 * value, or NULL */
    226 SCIP_Bool* dualboundcheck /**< pointer to store if the dual bound respects the given primal reference
    227 * value, or NULL */
    228 )
    229{
    230 SCIP_Bool localfeasible;
    231 SCIP_Bool localprimalboundcheck;
    232 SCIP_Bool localdualboundcheck;
    233 SCIP_RATIONAL* primviol;
    234 SCIP_RATIONAL* dualviol;
    235 SCIP_RATIONAL* pb;
    236 SCIP_RATIONAL* db;
    237 char rationalstring1[SCIP_MAXSTRLEN];
    238 char rationalstring2[SCIP_MAXSTRLEN];
    239
    240 assert(scip != NULL);
    241 assert(SCIPisExact(scip));
    242
    243 SCIP_CALL( SCIPrationalCreate(&primviol) );
    244 SCIP_CALL( SCIPrationalCreate(&dualviol) );
    247
    248 /* if no problem exists, there is no need for validation */
    250 {
    251 if( feasible != NULL )
    252 *feasible = TRUE;
    253 if( primalboundcheck != NULL )
    254 *primalboundcheck = TRUE;
    255 if( dualboundcheck != NULL )
    256 *dualboundcheck = TRUE;
    257
    258 return SCIP_OKAY;
    259 }
    260
    261 localfeasible = TRUE;
    262 localdualboundcheck = TRUE;
    263
    264 /* check the best solution for feasibility in the original problem */
    265 if( SCIPgetNSols(scip) > 0 )
    266 {
    267 SCIP_SOL* bestsol = SCIPgetBestSol(scip);
    268 assert(SCIPsolIsExact(bestsol));
    269
    270 assert(bestsol != NULL);
    271
    272 SCIP_CALL( SCIPcheckSolOrig(scip, bestsol, &localfeasible, !quiet, TRUE) );
    273 }
    274 else
    275 {
    276 localfeasible = TRUE;
    277 }
    278
    279 SCIPrationalSetFraction(primviol, 0LL, 1LL);
    280 SCIPrationalSetFraction(dualviol, 0LL, 1LL);
    281
    282 /* check the primal and dual bounds computed by SCIP against the external reference values within reference tolerance */
    283 /* solution for an infeasible problem */
    286 localprimalboundcheck = FALSE;
    287 else
    288 {
    289 /* check if reference primal bound is not better than the proven dual bound and, if SCIP claims to be optimal,
    290 * if the
    291 */
    294
    295 /* compute the relative violation between the primal bound and dual reference value, and vice versa */
    297 {
    298 SCIPrationalRelDiff(primviol, dualreference, pb);
    299 SCIPrationalRelDiff(dualviol, db, primalreference);
    300 }
    301 else
    302 {
    303 SCIPrationalRelDiff(primviol, pb, dualreference);
    304 SCIPrationalRelDiff(dualviol, primalreference, db);
    305 }
    306 localprimalboundcheck = SCIPrationalIsZero(primviol);
    307 localdualboundcheck = SCIPrationalIsZero(dualviol);
    308 }
    309
    310 if( !quiet )
    311 {
    312 int len;
    313
    314 SCIPinfoMessage(scip, NULL, "Validation : ");
    315 if( ! localfeasible )
    316 SCIPinfoMessage(scip, NULL, "Fail (infeasible)");
    317 else if( ! localprimalboundcheck )
    318 SCIPinfoMessage(scip, NULL, "Fail (primal bound)");
    319 else if( ! localdualboundcheck )
    320 SCIPinfoMessage(scip, NULL, "Fail (dual bound)");
    321 else
    322 SCIPinfoMessage(scip, NULL, "Success");
    323 SCIPinfoMessage(scip, NULL, "\n");
    324 SCIPinfoMessage(scip, NULL, " %-17s: %10u\n", "cons violation", !localfeasible);
    325 len = SCIPrationalToString(primviol, rationalstring1, SCIP_MAXSTRLEN);
    326 if( len == SCIP_MAXSTRLEN )
    327 {
    328 SCIPerrorMessage("rational too long to be converted to string \n");
    329 }
    330 len = SCIPrationalToString(dualreference, rationalstring2, SCIP_MAXSTRLEN);
    331 if( len == SCIP_MAXSTRLEN )
    332 {
    333 SCIPerrorMessage("rational too long to be converted to string \n");
    334 }
    335 SCIPinfoMessage(scip, NULL, " %-17s: %s (reference: %s)\n", "primal violation", rationalstring1, rationalstring2);
    336 len = SCIPrationalToString(dualviol, rationalstring1, SCIP_MAXSTRLEN);
    337 if( len == SCIP_MAXSTRLEN )
    338 {
    339 SCIPerrorMessage("rational too long to be converted to string \n");
    340 }
    341 len = SCIPrationalToString(primalreference, rationalstring2, SCIP_MAXSTRLEN);
    342 if( len == SCIP_MAXSTRLEN )
    343 {
    344 SCIPerrorMessage("rational too long to be converted to string \n");
    345 }
    346 SCIPinfoMessage(scip, NULL, " %-17s: %s (reference: %s)\n", "dual violation", rationalstring1, rationalstring2);
    347 }
    348
    349 if( feasible != NULL )
    350 *feasible = localfeasible;
    351 if( primalboundcheck != NULL )
    352 *primalboundcheck = localprimalboundcheck;
    353 if( dualboundcheck != NULL )
    354 *dualboundcheck = localdualboundcheck;
    355
    356 SCIPrationalFree(&primviol);
    357 SCIPrationalFree(&dualviol);
    358 SCIPrationalFree(&pb);
    359 SCIPrationalFree(&db);
    360
    361 return SCIP_OKAY;
    362}
    363
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define EPSP(x, eps)
    Definition: def.h:189
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define SCIP_UNKNOWN
    Definition: def.h:179
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
    Definition: scip_prob.c:1400
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
    Definition: misc.c:11162
    SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
    Definition: scip_param.c:307
    SCIP_Bool SCIPisExact(SCIP *scip)
    Definition: scip_exact.c:193
    SCIP_RETCODE SCIPrationalCreate(SCIP_RATIONAL **rational)
    Definition: rational.cpp:94
    int SCIPrationalToString(SCIP_RATIONAL *rational, char *str, int strlen)
    Definition: rational.cpp:1743
    SCIP_Bool SCIPrationalIsZero(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1624
    void SCIPrationalRelDiff(SCIP_RATIONAL *res, SCIP_RATIONAL *val1, SCIP_RATIONAL *val2)
    Definition: rational.cpp:1024
    void SCIPrationalSetFraction(SCIP_RATIONAL *res, SCIP_Longint nom, SCIP_Longint denom)
    Definition: rational.cpp:582
    SCIP_Bool SCIPrationalIsInfinity(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1660
    SCIP_Bool SCIPrationalIsNegInfinity(SCIP_RATIONAL *rational)
    Definition: rational.cpp:1670
    void SCIPrationalFree(SCIP_RATIONAL **rational)
    Definition: rational.cpp:450
    SCIP_RETCODE SCIPcheckSolOrig(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *feasible, SCIP_Bool printreason, SCIP_Bool completely)
    Definition: scip_sol.c:4380
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2981
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2882
    SCIP_Bool SCIPsolIsExact(SCIP_SOL *sol)
    Definition: sol.c:4150
    SCIP_Real SCIPgetPrimalbound(SCIP *scip)
    SCIP_Real SCIPgetDualbound(SCIP *scip)
    void SCIPgetDualboundExact(SCIP *scip, SCIP_RATIONAL *result)
    void SCIPgetPrimalboundExact(SCIP *scip, SCIP_RATIONAL *result)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_RETCODE SCIPchgFeastol(SCIP *scip, SCIP_Real feastol)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_RETCODE SCIPvalidateSolveExact(SCIP *scip, SCIP_RATIONAL *primalreference, SCIP_RATIONAL *dualreference, SCIP_Bool quiet, SCIP_Bool *feasible, SCIP_Bool *primalboundcheck, SCIP_Bool *dualboundcheck)
    SCIP_RETCODE SCIPvalidateSolve(SCIP *scip, SCIP_Real primalreference, SCIP_Real dualreference, SCIP_Real reftol, SCIP_Bool quiet, SCIP_Bool *feasible, SCIP_Bool *primalboundcheck, SCIP_Bool *dualboundcheck)
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    public data structures and miscellaneous methods
    public methods for primal CIP solutions
    wrapper for rational number arithmetic
    public methods for exact solving
    general public methods
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for solutions
    public methods for querying solving statistics
    public methods for validation
    @ SCIP_OBJSENSE_MAXIMIZE
    Definition: type_prob.h:47
    @ SCIP_OBJSENSE_MINIMIZE
    Definition: type_prob.h:48
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_PROBLEM
    Definition: type_set.h:45