1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the program and library */ 4 /* SCIP --- Solving Constraint Integer Programs */ 5 /* */ 6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */ 7 /* fuer Informationstechnik Berlin */ 8 /* */ 9 /* SCIP is distributed under the terms of the ZIB Academic License. */ 10 /* */ 11 /* You should have received a copy of the ZIB Academic License */ 12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */ 13 /* */ 14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 15 16 /**@file sol.h 17 * @ingroup INTERNALAPI 18 * @brief internal methods for storing primal CIP solutions 19 * @author Tobias Achterberg 20 */ 21 22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 23 24 #ifndef __SCIP_SOL_H__ 25 #define __SCIP_SOL_H__ 26 27 28 #include <stdio.h> 29 30 #include "scip/def.h" 31 #include "blockmemshell/memory.h" 32 #include "scip/type_retcode.h" 33 #include "scip/type_set.h" 34 #include "scip/type_stat.h" 35 #include "scip/type_lp.h" 36 #include "scip/type_nlp.h" 37 #include "scip/type_var.h" 38 #include "scip/type_prob.h" 39 #include "scip/type_sol.h" 40 #include "scip/type_primal.h" 41 #include "scip/type_tree.h" 42 #include "scip/type_heur.h" 43 #include "scip/pub_sol.h" 44 45 #ifdef __cplusplus 46 extern "C" { 47 #endif 48 49 /** creates primal CIP solution, initialized to zero */ 50 SCIP_RETCODE SCIPsolCreate( 51 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 52 BMS_BLKMEM* blkmem, /**< block memory */ 53 SCIP_SET* set, /**< global SCIP settings */ 54 SCIP_STAT* stat, /**< problem statistics data */ 55 SCIP_PRIMAL* primal, /**< primal data */ 56 SCIP_TREE* tree, /**< branch and bound tree, or NULL */ 57 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 58 ); 59 60 /** creates primal CIP solution in original problem space, initialized to the offset in the original problem */ 61 SCIP_RETCODE SCIPsolCreateOriginal( 62 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 63 BMS_BLKMEM* blkmem, /**< block memory */ 64 SCIP_SET* set, /**< global SCIP settings */ 65 SCIP_STAT* stat, /**< problem statistics data */ 66 SCIP_PROB* origprob, /**< original problem data */ 67 SCIP_PRIMAL* primal, /**< primal data */ 68 SCIP_TREE* tree, /**< branch and bound tree */ 69 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 70 ); 71 72 /** creates a copy of a primal CIP solution */ 73 SCIP_RETCODE SCIPsolCopy( 74 SCIP_SOL** sol, /**< pointer to store the copy of the primal CIP solution */ 75 BMS_BLKMEM* blkmem, /**< block memory */ 76 SCIP_SET* set, /**< global SCIP settings */ 77 SCIP_STAT* stat, /**< problem statistics data */ 78 SCIP_PRIMAL* primal, /**< primal data */ 79 SCIP_SOL* sourcesol /**< primal CIP solution to copy */ 80 ); 81 82 /** transformes given original solution to the transformed space; a corresponding transformed solution has to be given 83 * which is copied into the existing solution and freed afterwards 84 */ 85 SCIP_RETCODE SCIPsolTransform( 86 SCIP_SOL* sol, /**< primal CIP solution to change, living in original space */ 87 SCIP_SOL** transsol, /**< pointer to corresponding transformed primal CIP solution */ 88 BMS_BLKMEM* blkmem, /**< block memory */ 89 SCIP_SET* set, /**< global SCIP settings */ 90 SCIP_PRIMAL* primal /**< primal data */ 91 ); 92 93 /** adjusts solution values of implicit integer variables in handed solution. Solution objective value is not 94 * deteriorated by this method. 95 */ 96 SCIP_RETCODE SCIPsolAdjustImplicitSolVals( 97 SCIP_SOL* sol, /**< primal CIP solution */ 98 SCIP_SET* set, /**< global SCIP settings */ 99 SCIP_STAT* stat, /**< problem statistics data */ 100 SCIP_PROB* prob, /**< either original or transformed problem, depending on sol origin */ 101 SCIP_TREE* tree, /**< branch and bound tree */ 102 SCIP_Bool uselprows /**< should LP row information be considered for none-objective variables */ 103 ); 104 105 /** creates primal CIP solution, initialized to the current LP solution */ 106 SCIP_RETCODE SCIPsolCreateLPSol( 107 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 108 BMS_BLKMEM* blkmem, /**< block memory */ 109 SCIP_SET* set, /**< global SCIP settings */ 110 SCIP_STAT* stat, /**< problem statistics data */ 111 SCIP_PROB* prob, /**< transformed problem data */ 112 SCIP_PRIMAL* primal, /**< primal data */ 113 SCIP_TREE* tree, /**< branch and bound tree */ 114 SCIP_LP* lp, /**< current LP data */ 115 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 116 ); 117 118 /** creates primal CIP solution, initialized to the current NLP solution */ 119 SCIP_RETCODE SCIPsolCreateNLPSol( 120 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 121 BMS_BLKMEM* blkmem, /**< block memory */ 122 SCIP_SET* set, /**< global SCIP settings */ 123 SCIP_STAT* stat, /**< problem statistics data */ 124 SCIP_PRIMAL* primal, /**< primal data */ 125 SCIP_TREE* tree, /**< branch and bound tree */ 126 SCIP_NLP* nlp, /**< current NLP data */ 127 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 128 ); 129 130 /** creates primal CIP solution, initialized to the current relaxation solution */ 131 SCIP_RETCODE SCIPsolCreateRelaxSol( 132 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 133 BMS_BLKMEM* blkmem, /**< block memory */ 134 SCIP_SET* set, /**< global SCIP settings */ 135 SCIP_STAT* stat, /**< problem statistics data */ 136 SCIP_PRIMAL* primal, /**< primal data */ 137 SCIP_TREE* tree, /**< branch and bound tree */ 138 SCIP_RELAXATION* relaxation, /**< global relaxation data */ 139 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 140 ); 141 142 /** creates primal CIP solution, initialized to the current pseudo solution */ 143 SCIP_RETCODE SCIPsolCreatePseudoSol( 144 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 145 BMS_BLKMEM* blkmem, /**< block memory */ 146 SCIP_SET* set, /**< global SCIP settings */ 147 SCIP_STAT* stat, /**< problem statistics data */ 148 SCIP_PROB* prob, /**< transformed problem data */ 149 SCIP_PRIMAL* primal, /**< primal data */ 150 SCIP_TREE* tree, /**< branch and bound tree, or NULL */ 151 SCIP_LP* lp, /**< current LP data */ 152 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 153 ); 154 155 /** creates primal CIP solution, initialized to the current solution */ 156 SCIP_RETCODE SCIPsolCreateCurrentSol( 157 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 158 BMS_BLKMEM* blkmem, /**< block memory */ 159 SCIP_SET* set, /**< global SCIP settings */ 160 SCIP_STAT* stat, /**< problem statistics data */ 161 SCIP_PROB* prob, /**< transformed problem data */ 162 SCIP_PRIMAL* primal, /**< primal data */ 163 SCIP_TREE* tree, /**< branch and bound tree */ 164 SCIP_LP* lp, /**< current LP data */ 165 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 166 ); 167 168 /** creates partial primal CIP solution, initialized to unknown values */ 169 SCIP_RETCODE SCIPsolCreatePartial( 170 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 171 BMS_BLKMEM* blkmem, /**< block memory */ 172 SCIP_SET* set, /**< global SCIP settings */ 173 SCIP_STAT* stat, /**< problem statistics data */ 174 SCIP_PRIMAL* primal, /**< primal data */ 175 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 176 ); 177 178 /** creates primal CIP solution, initialized to unknown values */ 179 SCIP_RETCODE SCIPsolCreateUnknown( 180 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 181 BMS_BLKMEM* blkmem, /**< block memory */ 182 SCIP_SET* set, /**< global SCIP settings */ 183 SCIP_STAT* stat, /**< problem statistics data */ 184 SCIP_PRIMAL* primal, /**< primal data */ 185 SCIP_TREE* tree, /**< branch and bound tree */ 186 SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */ 187 ); 188 189 /** frees primal CIP solution */ 190 SCIP_RETCODE SCIPsolFree( 191 SCIP_SOL** sol, /**< pointer to primal CIP solution */ 192 BMS_BLKMEM* blkmem, /**< block memory */ 193 SCIP_PRIMAL* primal /**< primal data */ 194 ); 195 196 /** copies current LP solution into CIP solution by linking */ 197 SCIP_RETCODE SCIPsolLinkLPSol( 198 SCIP_SOL* sol, /**< primal CIP solution */ 199 SCIP_SET* set, /**< global SCIP settings */ 200 SCIP_STAT* stat, /**< problem statistics data */ 201 SCIP_PROB* prob, /**< transformed problem data */ 202 SCIP_TREE* tree, /**< branch and bound tree */ 203 SCIP_LP* lp /**< current LP data */ 204 ); 205 206 /** copies current NLP solution into CIP solution by linking */ 207 SCIP_RETCODE SCIPsolLinkNLPSol( 208 SCIP_SOL* sol, /**< primal CIP solution */ 209 SCIP_STAT* stat, /**< problem statistics data */ 210 SCIP_TREE* tree, /**< branch and bound tree */ 211 SCIP_NLP* nlp /**< current NLP data */ 212 ); 213 214 /** copies current relaxation solution into CIP solution by linking */ 215 SCIP_RETCODE SCIPsolLinkRelaxSol( 216 SCIP_SOL* sol, /**< primal CIP solution */ 217 SCIP_SET* set, /**< global SCIP settings */ 218 SCIP_STAT* stat, /**< problem statistics data */ 219 SCIP_TREE* tree, /**< branch and bound tree */ 220 SCIP_RELAXATION* relaxation /**< global relaxation data */ 221 ); 222 223 /** copies current pseudo solution into CIP solution by linking */ 224 SCIP_RETCODE SCIPsolLinkPseudoSol( 225 SCIP_SOL* sol, /**< primal CIP solution */ 226 SCIP_SET* set, /**< global SCIP settings */ 227 SCIP_STAT* stat, /**< problem statistics data */ 228 SCIP_PROB* prob, /**< transformed problem data */ 229 SCIP_TREE* tree, /**< branch and bound tree, or NULL */ 230 SCIP_LP* lp /**< current LP data */ 231 ); 232 233 /** copies current solution (LP or pseudo solution) into CIP solution by linking */ 234 SCIP_RETCODE SCIPsolLinkCurrentSol( 235 SCIP_SOL* sol, /**< primal CIP solution */ 236 SCIP_SET* set, /**< global SCIP settings */ 237 SCIP_STAT* stat, /**< problem statistics data */ 238 SCIP_PROB* prob, /**< transformed problem data */ 239 SCIP_TREE* tree, /**< branch and bound tree */ 240 SCIP_LP* lp /**< current LP data */ 241 ); 242 243 /** clears primal CIP solution */ 244 SCIP_RETCODE SCIPsolClear( 245 SCIP_SOL* sol, /**< primal CIP solution */ 246 SCIP_STAT* stat, /**< problem statistics data */ 247 SCIP_TREE* tree /**< branch and bound tree */ 248 ); 249 250 /** declares all entries in the primal CIP solution to be unknown */ 251 SCIP_RETCODE SCIPsolSetUnknown( 252 SCIP_SOL* sol, /**< primal CIP solution */ 253 SCIP_STAT* stat, /**< problem statistics data */ 254 SCIP_TREE* tree /**< branch and bound tree */ 255 ); 256 257 /** stores solution values of variables in solution's own array */ 258 SCIP_RETCODE SCIPsolUnlink( 259 SCIP_SOL* sol, /**< primal CIP solution */ 260 SCIP_SET* set, /**< global SCIP settings */ 261 SCIP_PROB* prob /**< transformed problem data */ 262 ); 263 264 /** sets value of variable in primal CIP solution */ 265 SCIP_RETCODE SCIPsolSetVal( 266 SCIP_SOL* sol, /**< primal CIP solution */ 267 SCIP_SET* set, /**< global SCIP settings */ 268 SCIP_STAT* stat, /**< problem statistics data */ 269 SCIP_TREE* tree, /**< branch and bound tree */ 270 SCIP_VAR* var, /**< variable to add to solution */ 271 SCIP_Real val /**< solution value of variable */ 272 ); 273 274 /** increases value of variable in primal CIP solution */ 275 SCIP_RETCODE SCIPsolIncVal( 276 SCIP_SOL* sol, /**< primal CIP solution */ 277 SCIP_SET* set, /**< global SCIP settings */ 278 SCIP_STAT* stat, /**< problem statistics data */ 279 SCIP_TREE* tree, /**< branch and bound tree */ 280 SCIP_VAR* var, /**< variable to increase solution value for */ 281 SCIP_Real incval /**< increment for solution value of variable */ 282 ); 283 284 /** returns value of variable in primal CIP solution */ 285 SCIP_Real SCIPsolGetVal( 286 SCIP_SOL* sol, /**< primal CIP solution */ 287 SCIP_SET* set, /**< global SCIP settings */ 288 SCIP_STAT* stat, /**< problem statistics data */ 289 SCIP_VAR* var /**< variable to get value for */ 290 ); 291 292 /** returns value of variable in primal ray represented by primal CIP solution */ 293 SCIP_Real SCIPsolGetRayVal( 294 SCIP_SOL* sol, /**< primal CIP solution, representing a primal ray */ 295 SCIP_SET* set, /**< global SCIP settings */ 296 SCIP_STAT* stat, /**< problem statistics data */ 297 SCIP_VAR* var /**< variable to get value for */ 298 ); 299 300 301 /** gets objective value of primal CIP solution in transformed problem */ 302 SCIP_Real SCIPsolGetObj( 303 SCIP_SOL* sol, /**< primal CIP solution */ 304 SCIP_SET* set, /**< global SCIP settings */ 305 SCIP_PROB* transprob, /**< tranformed problem data */ 306 SCIP_PROB* origprob /**< original problem data */ 307 ); 308 309 /** updates primal solutions after a change in a variable's objective value */ 310 void SCIPsolUpdateVarObj( 311 SCIP_SOL* sol, /**< primal CIP solution */ 312 SCIP_VAR* var, /**< problem variable */ 313 SCIP_Real oldobj, /**< old objective value */ 314 SCIP_Real newobj /**< new objective value */ 315 ); 316 317 /* mark the given solution as partial solution */ 318 SCIP_RETCODE SCIPsolMarkPartial( 319 SCIP_SOL* sol, /**< primal CIP solution */ 320 SCIP_SET* set, /**< global SCIP settings */ 321 SCIP_STAT* stat, /**< problem statistics */ 322 SCIP_VAR** vars, /**< problem variables */ 323 int nvars /**< number of problem variables */ 324 ); 325 326 /** checks primal CIP solution for feasibility 327 * 328 * @note The difference between SCIPsolCheck() and SCIPcheckSolOrig() is that modifiable constraints are handled 329 * differently. There might be some variables which do not have an original counter part (e.g. in 330 * branch-and-price). Therefore, modifiable constraints can not be double-checked in the original space. 331 */ 332 SCIP_RETCODE SCIPsolCheck( 333 SCIP_SOL* sol, /**< primal CIP solution */ 334 SCIP_SET* set, /**< global SCIP settings */ 335 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 336 BMS_BLKMEM* blkmem, /**< block memory */ 337 SCIP_STAT* stat, /**< problem statistics */ 338 SCIP_PROB* prob, /**< transformed problem data */ 339 SCIP_Bool printreason, /**< Should all reasons of violations be printed? */ 340 SCIP_Bool completely, /**< Should all violations be checked? */ 341 SCIP_Bool checkbounds, /**< Should the bounds of the variables be checked? */ 342 SCIP_Bool checkintegrality, /**< Has integrality to be checked? */ 343 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */ 344 SCIP_Bool* feasible /**< stores whether solution is feasible */ 345 ); 346 347 /** try to round given solution */ 348 SCIP_RETCODE SCIPsolRound( 349 SCIP_SOL* sol, /**< primal solution */ 350 SCIP_SET* set, /**< global SCIP settings */ 351 SCIP_STAT* stat, /**< problem statistics data */ 352 SCIP_PROB* prob, /**< transformed problem data */ 353 SCIP_TREE* tree, /**< branch and bound tree */ 354 SCIP_Bool* success /**< pointer to store whether rounding was successful */ 355 ); 356 357 /** updates the solution value sums in variables by adding the value in the given solution */ 358 void SCIPsolUpdateVarsum( 359 SCIP_SOL* sol, /**< primal CIP solution */ 360 SCIP_SET* set, /**< global SCIP settings */ 361 SCIP_STAT* stat, /**< problem statistics data */ 362 SCIP_PROB* prob, /**< transformed problem data */ 363 SCIP_Real weight /**< weight of solution in weighted average */ 364 ); 365 366 /** retransforms solution to original problem space */ 367 SCIP_RETCODE SCIPsolRetransform( 368 SCIP_SOL* sol, /**< primal CIP solution */ 369 SCIP_SET* set, /**< global SCIP settings */ 370 SCIP_STAT* stat, /**< problem statistics data */ 371 SCIP_PROB* origprob, /**< original problem */ 372 SCIP_PROB* transprob, /**< transformed problem */ 373 SCIP_Bool* hasinfval /**< pointer to store whether the solution has infinite values */ 374 ); 375 376 /** recomputes the objective value of an original solution, e.g., when transferring solutions 377 * from the solution pool (objective coefficients might have changed in the meantime) 378 */ 379 void SCIPsolRecomputeObj( 380 SCIP_SOL* sol, /**< primal CIP solution */ 381 SCIP_SET* set, /**< global SCIP settings */ 382 SCIP_STAT* stat, /**< problem statistics data */ 383 SCIP_PROB* origprob /**< original problem */ 384 ); 385 386 387 /** returns whether the given solutions in transformed space are equal */ 388 SCIP_Bool SCIPsolsAreEqual( 389 SCIP_SOL* sol1, /**< first primal CIP solution */ 390 SCIP_SOL* sol2, /**< second primal CIP solution */ 391 SCIP_SET* set, /**< global SCIP settings */ 392 SCIP_STAT* stat, /**< problem statistics data */ 393 SCIP_PROB* origprob, /**< original problem */ 394 SCIP_PROB* transprob /**< transformed problem after presolve */ 395 ); 396 397 /** outputs non-zero elements of solution to file stream */ 398 SCIP_RETCODE SCIPsolPrint( 399 SCIP_SOL* sol, /**< primal CIP solution */ 400 SCIP_SET* set, /**< global SCIP settings */ 401 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 402 SCIP_STAT* stat, /**< problem statistics data */ 403 SCIP_PROB* prob, /**< problem data (original or transformed) */ 404 SCIP_PROB* transprob, /**< transformed problem data or NULL (to display priced variables) */ 405 FILE* file, /**< output file (or NULL for standard output) */ 406 SCIP_Bool mipstart, /**< should only discrete variables be printed? */ 407 SCIP_Bool printzeros /**< should variables set to zero be printed? */ 408 ); 409 410 /** outputs non-zero elements of solution representing a ray to file stream */ 411 SCIP_RETCODE SCIPsolPrintRay( 412 SCIP_SOL* sol, /**< primal CIP solution */ 413 SCIP_SET* set, /**< global SCIP settings */ 414 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */ 415 SCIP_STAT* stat, /**< problem statistics data */ 416 SCIP_PROB* prob, /**< problem data (original or transformed) */ 417 SCIP_PROB* transprob, /**< transformed problem data or NULL (to display priced variables) */ 418 FILE* file, /**< output file (or NULL for standard output) */ 419 SCIP_Bool printzeros /**< should variables set to zero be printed? */ 420 ); 421 422 423 /** reset violations of a solution */ 424 void SCIPsolResetViolations( 425 SCIP_SOL* sol /**< primal CIP solution */ 426 ); 427 428 /** update integrality violation of a solution */ 429 void SCIPsolUpdateIntegralityViolation( 430 SCIP_SOL* sol, /**< primal CIP solution */ 431 SCIP_Real absviolintegrality /**< absolute violation of integrality */ 432 ); 433 434 /** update bound violation of a solution */ 435 void SCIPsolUpdateBoundViolation( 436 SCIP_SOL* sol, /**< primal CIP solution */ 437 SCIP_Real absviolbounds, /**< absolute violation of bounds */ 438 SCIP_Real relviolbounds /**< relative violation of bounds */ 439 ); 440 441 /** update LP row violation of a solution */ 442 void SCIPsolUpdateLPRowViolation( 443 SCIP_SOL* sol, /**< primal CIP solution */ 444 SCIP_Real absviollprows, /**< absolute violation of LP rows */ 445 SCIP_Real relviollprows /**< relative violation of LP rows */ 446 ); 447 448 /** update constraint violation of a solution */ 449 void SCIPsolUpdateConsViolation( 450 SCIP_SOL* sol, /**< primal CIP solution */ 451 SCIP_Real absviolcons, /**< absolute violation of constraint */ 452 SCIP_Real relviolcons /**< relative violation of constraint */ 453 ); 454 455 /** update violation of a constraint that is represented in the LP */ 456 void SCIPsolUpdateLPConsViolation( 457 SCIP_SOL* sol, /**< primal CIP solution */ 458 SCIP_Real absviol, /**< absolute violation of constraint */ 459 SCIP_Real relviol /**< relative violation of constraint */ 460 ); 461 462 463 464 /* In debug mode, the following methods are implemented as function calls to ensure 465 * type validity. 466 */ 467 468 /** adds value to the objective value of a given original primal CIP solution */ 469 void SCIPsolOrigAddObjval( 470 SCIP_SOL* sol, /**< primal CIP solution */ 471 SCIP_Real addval /**< offset value to add */ 472 ); 473 474 /** gets current position of solution in array of existing solutions of primal data */ 475 int SCIPsolGetPrimalIndex( 476 SCIP_SOL* sol /**< primal CIP solution */ 477 ); 478 479 /** sets current position of solution in array of existing solutions of primal data */ 480 void SCIPsolSetPrimalIndex( 481 SCIP_SOL* sol, /**< primal CIP solution */ 482 int primalindex /**< new primal index of solution */ 483 ); 484 485 #ifdef NDEBUG 486 487 /* In optimized mode, the function calls are overwritten by defines to reduce the number of function calls and 488 * speed up the algorithms. 489 */ 490 491 #define SCIPsolOrigAddObjval(sol, addval) ((sol)->obj += (addval)) 492 #define SCIPsolGetPrimalIndex(sol) ((sol)->primalindex) 493 #define SCIPsolSetPrimalIndex(sol,idx) { (sol)->primalindex = idx; } 494 495 #endif 496 497 #ifdef __cplusplus 498 } 499 #endif 500 501 #endif 502