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