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 13 #include "LinearSpec.h" 14 #include "Variable.h" 15 16 17 // Toggle debug output 18 //#define DEBUG_CONSTRAINT 19 20 #ifdef DEBUG_CONSTRAINT 21 # define STRACE(x) debug_printf x 22 #else 23 # define STRACE(x) ; 24 #endif 25 26 27 /** 28 * Gets the index of the constraint. 29 * 30 * @return the index of the constraint 31 */ 32 int32 33 Constraint::Index() const 34 { 35 int32 i = fLS->Constraints().IndexOf(this); 36 if (i == -1) { 37 STRACE(("Constraint not part of fLS->Constraints().")); 38 return -1; 39 } 40 return i + 1; 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 if (!fIsValid) 225 return; 226 227 if (fDNegObjSummand == NULL) { 228 fDNegObjSummand = new(std::nothrow) Summand(value, fLS->AddVariable()); 229 fLS->ObjectiveFunction()->AddItem(fDNegObjSummand); 230 fLS->UpdateLeftSide(this); 231 fLS->UpdateObjectiveFunction(); 232 return; 233 } 234 235 if (value == fDNegObjSummand->Coeff()) 236 return; 237 238 fDNegObjSummand->SetCoeff(value); 239 fLS->UpdateObjectiveFunction(); 240 } 241 242 243 /** 244 * Gets the penalty coefficient for positive deviations. 245 * 246 * @return the penalty coefficient 247 */ 248 double 249 Constraint::PenaltyPos() const 250 { 251 return fPenaltyPos; 252 } 253 254 255 /** 256 * The penalty coefficient for negative deviations from the soft constraint's 257 * exact solution, i.e. if the left side is too small. 258 * @param value coefficient of positive penalty <code>double</code> 259 */ 260 void 261 Constraint::SetPenaltyPos(double value) 262 { 263 fPenaltyPos = value; 264 265 if (!fIsValid) 266 return; 267 268 if (fDPosObjSummand == NULL) { 269 fDPosObjSummand = new(std::nothrow) Summand(value, fLS->AddVariable()); 270 fLS->ObjectiveFunction()->AddItem(fDPosObjSummand); 271 fLS->UpdateLeftSide(this); 272 fLS->UpdateObjectiveFunction(); 273 return; 274 } 275 276 if (value == fDPosObjSummand->Coeff()) 277 return; 278 279 fDPosObjSummand->SetCoeff(value); 280 fLS->UpdateObjectiveFunction(); 281 } 282 283 284 const char* 285 Constraint::Label() 286 { 287 return fLabel.String(); 288 } 289 290 291 void 292 Constraint::SetLabel(const char* label) 293 { 294 fLabel = label; 295 } 296 297 298 void 299 Constraint::WriteXML(BFile* file) 300 { 301 if (!file->IsWritable()) 302 return; 303 304 char buffer[200]; 305 306 file->Write(buffer, sprintf(buffer, "\t<constraint>\n")); 307 file->Write(buffer, sprintf(buffer, "\t\t<leftside>\n")); 308 309 Summand* summand; 310 for (int32 i = 0; i < fLeftSide->CountItems(); i++) { 311 summand = (Summand*)fLeftSide->ItemAt(i); 312 file->Write(buffer, sprintf(buffer, "\t\t\t<summand>\n")); 313 file->Write(buffer, sprintf(buffer, "\t\t\t\t<coeff>%f</coeff>\n", 314 summand->Coeff())); 315 BString varStr = *(summand->Var()); 316 file->Write(buffer, sprintf(buffer, "\t\t\t\t<var>%s</var>\n", 317 varStr.String())); 318 file->Write(buffer, sprintf(buffer, "\t\t\t</summand>\n")); 319 } 320 321 file->Write(buffer, sprintf(buffer, "\t\t</leftside>\n")); 322 323 const char* op = "??"; 324 if (fOp == OperatorType(EQ)) 325 op = "EQ"; 326 else if (fOp == OperatorType(LE)) 327 op = "LE"; 328 else if (fOp == OperatorType(GE)) 329 op = "GE"; 330 331 file->Write(buffer, sprintf(buffer, "\t\t<op>%s</op>\n", op)); 332 file->Write(buffer, sprintf(buffer, "\t\t<rightside>%f</rightside>\n", fRightSide)); 333 //~ file->Write(buffer, sprintf(buffer, "\t\t<penaltyneg>%s</penaltyneg>\n", PenaltyNeg())); 334 //~ file->Write(buffer, sprintf(buffer, "\t\t<penaltypos>%s</penaltypos>\n", PenaltyPos())); 335 file->Write(buffer, sprintf(buffer, "\t</constraint>\n")); 336 } 337 338 339 /** 340 * Gets the slack variable for the negative variations. 341 * 342 * @return the slack variable for the negative variations 343 */ 344 Variable* 345 Constraint::DNeg() const 346 { 347 if (fDNegObjSummand == NULL) 348 return NULL; 349 return fDNegObjSummand->Var(); 350 } 351 352 353 /** 354 * Gets the slack variable for the positive variations. 355 * 356 * @return the slack variable for the positive variations 357 */ 358 Variable* 359 Constraint::DPos() const 360 { 361 if (fDPosObjSummand == NULL) 362 return NULL; 363 return fDPosObjSummand->Var(); 364 } 365 366 367 bool 368 Constraint::IsValid() 369 { 370 return fIsValid; 371 } 372 373 374 void 375 Constraint::Invalidate() 376 { 377 STRACE(("Constraint::Invalidate() on %d\n", this)); 378 379 if (!fIsValid) 380 return; 381 382 fIsValid = false; 383 fLS->RemoveConstraint(this, false); 384 } 385 386 387 Constraint::operator BString() const 388 { 389 BString string; 390 GetString(string); 391 return string; 392 } 393 394 395 void 396 Constraint::GetString(BString& string) const 397 { 398 string << "Constraint "; 399 string << fLabel; 400 string << "(" << (int32)this << "): "; 401 402 if (fIsValid) { 403 for (int i = 0; i < fLeftSide->CountItems(); i++) { 404 Summand* s = static_cast<Summand*>(fLeftSide->ItemAt(i)); 405 string << (float)s->Coeff() << "*"; 406 s->Var()->GetString(string); 407 string << " "; 408 } 409 string << ((fOp == OperatorType(EQ)) ? "== " 410 : (fOp == OperatorType(GE)) ? ">= " 411 : (fOp == OperatorType(LE)) ? "<= " 412 : "?? "); 413 string << (float)fRightSide; 414 string << " PenaltyPos=" << (float)PenaltyPos(); 415 string << " PenaltyNeg=" << (float)PenaltyNeg(); 416 } else 417 string << "invalid"; 418 } 419 420 421 /** 422 * Constructor. 423 */ 424 Constraint::Constraint(LinearSpec* ls, SummandList* summands, OperatorType op, 425 double rightSide, double penaltyNeg, double penaltyPos) 426 : 427 fLS(ls), 428 fLeftSide(summands), 429 fOp(op), 430 fRightSide(rightSide), 431 fPenaltyNeg(penaltyNeg), 432 fPenaltyPos(penaltyPos), 433 fDNegObjSummand(NULL), 434 fDPosObjSummand(NULL), 435 fIsValid(true) 436 { 437 438 } 439 440 441 /** 442 * Destructor. 443 * Removes the constraint from its specification and deletes all the summands. 444 */ 445 Constraint::~Constraint() 446 { 447 Invalidate(); 448 449 for (int32 i = 0; i < fLeftSide->CountItems(); i++) 450 delete (Summand*)fLeftSide->ItemAt(i); 451 delete fLeftSide; 452 fLeftSide = NULL; 453 } 454 455