1 /* 2 * Copyright 2007-2008, Christof Lutteroth, lutteroth@cs.auckland.ac.nz 3 * Copyright 2007-2008, James Kim, jkim202@ec.auckland.ac.nz 4 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de> 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "Constraint.h" 10 11 #include <new> 12 #include <stdio.h> 13 14 #include "LinearSpec.h" 15 #include "Variable.h" 16 17 18 // Toggle debug output 19 //#define DEBUG_CONSTRAINT 20 21 #ifdef DEBUG_CONSTRAINT 22 # define STRACE(x) debug_printf x 23 #else 24 # define STRACE(x) ; 25 #endif 26 27 28 /** 29 * Gets the index of the constraint. 30 * 31 * @return the index of the constraint 32 */ 33 int32 34 Constraint::Index() const 35 { 36 int32 i = fLS->Constraints().IndexOf(this); 37 if (i == -1) 38 STRACE(("Constraint not part of fLS->Constraints().")); 39 40 return i; 41 } 42 43 44 /** 45 * Gets the left side of the constraint. 46 * 47 * @return pointer to a BList containing the summands on the left side of the constraint 48 */ 49 SummandList* 50 Constraint::LeftSide() 51 { 52 return fLeftSide; 53 } 54 55 56 /** 57 * Sets the summands on the left side of the constraint. 58 * The old summands are NOT deleted. 59 * 60 * @param summands a BList containing the Summand objects that make up the new left side 61 */ 62 void 63 Constraint::SetLeftSide(SummandList* summands) 64 { 65 if (!fIsValid) 66 return; 67 68 fLeftSide = summands; 69 fLS->UpdateLeftSide(this); 70 } 71 72 73 void 74 Constraint::SetLeftSide(double coeff1, Variable* var1) 75 { 76 if (!fIsValid) 77 return; 78 79 for (int i=0; i<fLeftSide->CountItems(); i++) 80 delete fLeftSide->ItemAt(i); 81 fLeftSide->MakeEmpty(); 82 fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1)); 83 fLS->UpdateLeftSide(this); 84 } 85 86 87 void 88 Constraint::SetLeftSide(double coeff1, Variable* var1, 89 double coeff2, Variable* var2) 90 { 91 if (!fIsValid) 92 return; 93 94 for (int i=0; i<fLeftSide->CountItems(); i++) 95 delete fLeftSide->ItemAt(i); 96 fLeftSide->MakeEmpty(); 97 fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1)); 98 fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2)); 99 fLS->UpdateLeftSide(this); 100 } 101 102 103 void 104 Constraint::SetLeftSide(double coeff1, Variable* var1, 105 double coeff2, Variable* var2, 106 double coeff3, Variable* var3) 107 { 108 if (!fIsValid) 109 return; 110 111 for (int i=0; i<fLeftSide->CountItems(); i++) 112 delete fLeftSide->ItemAt(i); 113 fLeftSide->MakeEmpty(); 114 fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1)); 115 fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2)); 116 fLeftSide->AddItem(new(std::nothrow) Summand(coeff3, var3)); 117 fLS->UpdateLeftSide(this); 118 } 119 120 121 void 122 Constraint::SetLeftSide(double coeff1, Variable* var1, 123 double coeff2, Variable* var2, 124 double coeff3, Variable* var3, 125 double coeff4, Variable* var4) 126 { 127 if (!fIsValid) 128 return; 129 130 for (int i=0; i<fLeftSide->CountItems(); i++) 131 delete fLeftSide->ItemAt(i); 132 fLeftSide->MakeEmpty(); 133 fLeftSide->AddItem(new(std::nothrow) Summand(coeff1, var1)); 134 fLeftSide->AddItem(new(std::nothrow) Summand(coeff2, var2)); 135 fLeftSide->AddItem(new(std::nothrow) Summand(coeff3, var3)); 136 fLeftSide->AddItem(new(std::nothrow) Summand(coeff4, var4)); 137 fLS->UpdateLeftSide(this); 138 } 139 140 141 /** 142 * Gets the operator used for this constraint. 143 * 144 * @return the operator used for this constraint 145 */ 146 OperatorType 147 Constraint::Op() 148 { 149 return fOp; 150 } 151 152 153 /** 154 * Sets the operator used for this constraint. 155 * 156 * @param value operator 157 */ 158 void 159 Constraint::SetOp(OperatorType value) 160 { 161 if (!fIsValid) 162 return; 163 164 fOp = value; 165 fLS->UpdateOperator(this); 166 } 167 168 169 /** 170 * Gets the constant value that is on the right side of the operator. 171 * 172 * @return the constant value that is on the right side of the operator 173 */ 174 double 175 Constraint::RightSide() const 176 { 177 return fRightSide; 178 } 179 180 181 /** 182 * Sets the constant value that is on the right side of the operator. 183 * 184 * @param value constant value that is on the right side of the operator 185 */ 186 void 187 Constraint::SetRightSide(double value) 188 { 189 if (!fIsValid) 190 return; 191 192 if (fRightSide == value) 193 return; 194 195 fRightSide = value; 196 197 fLS->UpdateRightSide(this); 198 } 199 200 201 /** 202 * Gets the penalty coefficient for negative deviations. 203 * 204 * @return the penalty coefficient 205 */ 206 double 207 Constraint::PenaltyNeg() const 208 { 209 return fPenaltyNeg; 210 } 211 212 213 /** 214 * The penalty coefficient for negative deviations from the soft constraint's exact solution, 215 * i.e. if the left side is too large. 216 * 217 * @param value coefficient of negative penalty <code>double</code> 218 */ 219 void 220 Constraint::SetPenaltyNeg(double value) 221 { 222 fPenaltyNeg = value; 223 224 fLS->UpdateLeftSide(this); 225 } 226 227 228 /** 229 * Gets the penalty coefficient for positive deviations. 230 * 231 * @return the penalty coefficient 232 */ 233 double 234 Constraint::PenaltyPos() const 235 { 236 return fPenaltyPos; 237 } 238 239 240 /** 241 * The penalty coefficient for negative deviations from the soft constraint's 242 * exact solution, i.e. if the left side is too small. 243 * @param value coefficient of positive penalty <code>double</code> 244 */ 245 void 246 Constraint::SetPenaltyPos(double value) 247 { 248 fPenaltyPos = value; 249 250 fLS->UpdateLeftSide(this); 251 } 252 253 254 const char* 255 Constraint::Label() 256 { 257 return fLabel.String(); 258 } 259 260 261 void 262 Constraint::SetLabel(const char* label) 263 { 264 fLabel = label; 265 } 266 267 268 /** 269 * Gets the slack variable for the negative variations. 270 * 271 * @return the slack variable for the negative variations 272 */ 273 Variable* 274 Constraint::DNeg() const 275 { 276 if (fDNegObjSummand == NULL) 277 return NULL; 278 return fDNegObjSummand->Var(); 279 } 280 281 282 /** 283 * Gets the slack variable for the positive variations. 284 * 285 * @return the slack variable for the positive variations 286 */ 287 Variable* 288 Constraint::DPos() const 289 { 290 if (fDPosObjSummand == NULL) 291 return NULL; 292 return fDPosObjSummand->Var(); 293 } 294 295 296 bool 297 Constraint::IsSoft() const 298 { 299 if (fPenaltyNeg > 0. && fOp != kLE) 300 return true; 301 302 if (fPenaltyPos > 0. && fOp != kGE) 303 return true; 304 return false; 305 } 306 307 308 bool 309 Constraint::IsValid() 310 { 311 return fIsValid; 312 } 313 314 315 void 316 Constraint::Invalidate() 317 { 318 STRACE(("Constraint::Invalidate() on %d\n", this)); 319 320 if (!fIsValid) 321 return; 322 323 fIsValid = false; 324 fLS->RemoveConstraint(this, false); 325 } 326 327 328 BString 329 Constraint::ToString() const 330 { 331 BString string; 332 string << "Constraint "; 333 string << fLabel; 334 string << "(" << (int32)this << "): "; 335 336 if (fIsValid) { 337 for (int i = 0; i < fLeftSide->CountItems(); i++) { 338 Summand* s = static_cast<Summand*>(fLeftSide->ItemAt(i)); 339 string << (float)s->Coeff() << "*"; 340 string << "x"; 341 string << s->Var()->Index() - 1; 342 string << " "; 343 } 344 string << ((fOp == kEQ) ? "== " 345 : (fOp == kGE) ? ">= " 346 : (fOp == kLE) ? "<= " 347 : "?? "); 348 string << (float)fRightSide; 349 string << " PenaltyPos=" << (float)PenaltyPos(); 350 string << " PenaltyNeg=" << (float)PenaltyNeg(); 351 } else 352 string << "invalid"; 353 return string; 354 } 355 356 357 void 358 Constraint::PrintToStream() 359 { 360 BString string = ToString(); 361 printf("%s\n", string.String()); 362 } 363 364 365 /** 366 * Constructor. 367 */ 368 Constraint::Constraint(LinearSpec* ls, SummandList* summands, OperatorType op, 369 double rightSide, double penaltyNeg, double penaltyPos) 370 : 371 fLS(ls), 372 fLeftSide(summands), 373 fOp(op), 374 fRightSide(rightSide), 375 fPenaltyNeg(penaltyNeg), 376 fPenaltyPos(penaltyPos), 377 fDNegObjSummand(NULL), 378 fDPosObjSummand(NULL), 379 fIsValid(true) 380 { 381 382 } 383 384 385 /** 386 * Destructor. 387 * Removes the constraint from its specification and deletes all the summands. 388 */ 389 Constraint::~Constraint() 390 { 391 Invalidate(); 392 393 for (int32 i = 0; i < fLeftSide->CountItems(); i++) 394 delete (Summand*)fLeftSide->ItemAt(i); 395 delete fLeftSide; 396 fLeftSide = NULL; 397 } 398 399