1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the class library                   */
4    	/*       SoPlex --- the Sequential object-oriented simPlex.                  */
5    	/*                                                                           */
6    	/*  Copyright (c) 1996-2023 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 SoPlex; see the file LICENSE. If not email to soplex@zib.de.  */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file  validation.hpp
26   	 * @brief Validation object for soplex solutions
27   	 */
28   	
29   	namespace soplex
30   	{
31   	
32   	template <class R>
33   	bool Validation<R>::updateExternalSolution(const std::string& solution)
34   	{
35   	   validate = true;
36   	   validatesolution = solution;
37   	
38   	   if(solution == "+infinity")
39   	   {
40   	      return true;
41   	   }
42   	   else if(solution == "-infinity")
43   	   {
44   	      return true;
45   	   }
46   	   else
47   	   {
48   	      char* tailptr;
49   	      strtod(solution.c_str(), &tailptr);
50   	
51   	      if(*tailptr)
52   	      {
53   	         //conversion failed because the input wasn't a number
54   	         return false;
55   	      }
56   	   }
57   	
58   	   return true;
59   	}
60   	
61   	
62   	/// updates the tolerance used for validation
63   	template <class R>
64   	bool Validation<R>::updateValidationTolerance(const std::string& tolerance)
65   	{
66   	   char* tailptr;
67   	   validatetolerance = strtod(tolerance.c_str(), &tailptr);
68   	
69   	   if(*tailptr)
70   	   {
71   	      //conversion failed because the input wasn't a number
72   	      return false;
73   	   }
74   	
75   	   return true;
76   	}
77   	
78   	template <class R>
79   	void Validation<R>::validateSolveReal(SoPlexBase<R>& soplex)
80   	{
81   	   bool passedValidation = true;
82   	   std::string reason = "";
83   	   R objViolation = 0.0;
84   	   R maxBoundViolation = 0.0;
85   	   R maxRowViolation = 0.0;
86   	   R maxRedCostViolation = 0.0;
87   	   R maxDualViolation = 0.0;
88   	   R sumBoundViolation = 0.0;
89   	   R sumRowViolation = 0.0;
90   	   R sumRedCostViolation = 0.0;
91   	   R sumDualViolation = 0.0;
92   	   R sol;
93   	
94   	   std::ostream& os = soplex.spxout.getStream(SPxOut::INFO1);
95   	
96   	   if(validatesolution == "+infinity")
97   	   {
98   	      sol = soplex.realParam(SoPlexBase<R>::INFTY);
99   	   }
100  	   else if(validatesolution == "-infinity")
101  	   {
102  	      sol = -soplex.realParam(SoPlexBase<R>::INFTY);
103  	   }
104  	   else
105  	   {
106  	      sol = atof(validatesolution.c_str());
107  	   }
108  	
109  	   objViolation = spxAbs(sol - soplex.objValueReal());
110  	
111  	   // skip check in case presolving detected infeasibility/unboundedness
112  	   if(SPxSolverBase<R>::INForUNBD == soplex.status() &&
113  	         (sol == soplex.realParam(SoPlexBase<R>::INFTY)
114  	          || sol == -soplex.realParam(SoPlexBase<R>::INFTY)))
115  	      objViolation = 0.0;
116  	
117  	   if(! EQ(objViolation, R(0.0), validatetolerance))
118  	   {
119  	      passedValidation = false;
120  	      reason += "Objective Violation; ";
121  	   }
122  	
123  	   if(SPxSolverBase<R>::OPTIMAL == soplex.status())
124  	   {
125  	      soplex.getBoundViolation(maxBoundViolation, sumBoundViolation);
126  	      soplex.getRowViolation(maxRowViolation, sumRowViolation);
127  	      soplex.getRedCostViolation(maxRedCostViolation, sumRedCostViolation);
128  	      soplex.getDualViolation(maxDualViolation, sumDualViolation);
129  	
130  	      if(! LE(maxBoundViolation, validatetolerance, soplex.tolerances()->epsilon()))
131  	      {
132  	         passedValidation = false;
133  	         reason += "Bound Violation; ";
134  	      }
135  	
136  	      if(! LE(maxRowViolation, validatetolerance, soplex.tolerances()->epsilon()))
137  	      {
138  	         passedValidation = false;
139  	         reason += "Row Violation; ";
140  	      }
141  	
142  	      if(! LE(maxRedCostViolation, validatetolerance, soplex.tolerances()->epsilon()))
143  	      {
144  	         passedValidation = false;
145  	         reason += "Reduced Cost Violation; ";
146  	      }
147  	
148  	      if(! LE(maxDualViolation, validatetolerance, soplex.tolerances()->epsilon()))
149  	      {
150  	         passedValidation = false;
151  	         reason += "Dual Violation; ";
152  	      }
153  	   }
154  	
155  	   os << "\n";
156  	   os << "Validation          :";
157  	
158  	   if(passedValidation)
159  	      os << " Success\n";
160  	   else
161  	   {
162  	      reason[reason.length() - 2] = ']';
163  	      os << " Fail [" + reason + "\n";
164  	   }
165  	
166  	   os << "   Objective        : " << std::scientific << std::setprecision(
167  	         8) << objViolation << std::fixed << "\n";
168  	   os << "   Bound            : " << std::scientific << std::setprecision(
169  	         8) << maxBoundViolation << std::fixed << "\n";
170  	   os << "   Row              : " << std::scientific << std::setprecision(
171  	         8) << maxRowViolation << std::fixed << "\n";
172  	   os << "   Reduced Cost     : " << std::scientific << std::setprecision(
173  	         8) << maxRedCostViolation << std::fixed << "\n";
174  	   os << "   Dual             : " << std::scientific << std::setprecision(
175  	         8) << maxDualViolation << std::fixed << "\n";
176  	}
177  	
178  	} // namespace soplex
179