// Copyright (C) 2002, International Business Machines // Corporation and others. All Rights Reserved. #ifndef SbbCompareUser_H #define SbbCompareUser_H //############################################################################# /* These are alternative strategies for node traversal. They can take data etc for fine tuning At present the node list is stored as a heap and the "test" comparison function returns true if node y is better than node x. */ #include "SbbNode.hpp" #include "SbbCompareBase.hpp" /////ADDG /////SbbCompareActual //SbbCompareActual // oriNumUnsatisfied search class SbbCompareOriNumUnsatisfied : public SbbCompareBase{ public: // Default Constructor SbbCompareOriNumUnsatisfied () {test_=this;}; ~SbbCompareOriNumUnsatisfied() {}; // This returns true if the numUnsatisfied of node y is LESS than numUnsatisfied of node x virtual bool test (SbbNode * x, SbbNode * y) { return x->numberUnsatisfied() > y->numberUnsatisfied(); } }; // numUnsatisfiedMod search class SbbCompareNumUnsatisfiedMod : public SbbCompareBase{ public: // Default Constructor SbbCompareNumUnsatisfiedMod () {test_=this;}; ~SbbCompareNumUnsatisfiedMod() {}; // This returns true if the numUnsatisfiedMod of node y is LESS than numUnsatisfiedMod of node x virtual bool test (SbbNode * x, SbbNode * y) { return x->estimates()[numUnsatisfiedMod] > y->estimates()[numUnsatisfiedMod]; } }; // sumUnsatisfiedM search class SbbCompareSumUnsatisfied : public SbbCompareBase{ public: // Default Constructor SbbCompareSumUnsatisfied () {test_=this;}; ~SbbCompareSumUnsatisfied() {}; // This returns true if the sumUnsatisfied of node y is LESS than sumUnsatisfied of node x virtual bool test (SbbNode * x, SbbNode * y) { return x->estimates()[sumUnsatisfied]> y->estimates()[sumUnsatisfied]; } }; // the ratio of sumUnsatisfied to NumUnsatisfiedMod search class SbbCompareRatioSumToNumUnsatisfiedMod : public SbbCompareBase{ public: // Default Constructor SbbCompareRatioSumToNumUnsatisfiedMod () {test_=this;}; ~SbbCompareRatioSumToNumUnsatisfiedMod() {}; // This returns true if the the ratio of sumUnsatisfied to numUnsatisfiedMod of node y is LESS than the ratio of sumUnsatisfied to numUnsatisfiedMod of node x virtual bool test (SbbNode * x, SbbNode * y) { return (x->estimates()[sumUnsatisfied]/x->estimates()[numUnsatisfiedMod] ) > (y->estimates()[sumUnsatisfied]/ y->estimates()[numUnsatisfiedMod] ); } }; // the weighted sum of sumUnsatisfied to numUnsatisfiedMod search class SbbCompareWeightedSumToNumUnsatisfiedMod : public SbbCompareBase{ public: // Weights double alpha_, beta_; // Default Constructor SbbCompareWeightedSumToNumUnsatisfiedMod () : alpha_(1.0), beta_(1) {test_=this;}; ~SbbCompareWeightedSumToNumUnsatisfiedMod() {}; // This returns true if the the weightsd sum of sumUnsatisfied to numUnsatisfiedMod of node y is LESS than the weighte sSum of sumUnsatisfied to numUnsatisfiedMod of node x virtual bool test (SbbNode * x, SbbNode * y) { return (alpha_*x->estimates()[sumUnsatisfied]+beta_*x->estimates()[numUnsatisfiedMod] ) > (alpha_*y->estimates()[sumUnsatisfied]+beta_*y->estimates()[numUnsatisfiedMod] ); } }; // search based on a;llowable variable values class SbbCompareAllowableVariableValues : public SbbCompareBase{ public: // Default Constructor SbbCompareAllowableVariableValues () {test_=this;}; ~SbbCompareAllowableVariableValues() {}; // This returns true if the allowable bariable values of node y is greater than allowable variable values of node x virtual bool test (SbbNode * x, SbbNode * y) { if (x->estimates()[AVVInfPart]< y->estimates()[AVVInfPart]) return false; if (x->estimates()[AVVInfPart]>y->estimates()[AVVInfPart]) return true; if (x->estimates()[AVVIntPart]>y->estimates()[AVVIntPart]) return true; else return false; } }; // Breadth first search class SbbCompareBreadth : public SbbCompareBase{ public: // Default Constructor SbbCompareBreadth () {test_=this;}; ~SbbCompareBreadth() {}; // This returns true if the breadth of node y is greater than breadth of node x virtual bool test (SbbNode * x, SbbNode * y) { return x->depth() > y->depth(); } }; // Random choice class SbbCompareRandom : public SbbCompareBase{ public: // Default Constructor SbbCompareRandom () {test_=this;}; ~SbbCompareRandom() {}; // This returns true randomly virtual bool test (SbbNode * x, SbbNode * y) { return (rand() %2)==0; } }; // computes and stores the value of a specified objective function estimate class SbbObjEstimate { public: // type of estimate and its value enum objEstimate_t estimateType_; double estimateValue_; // Default Constructor SbbObjEstimate (enum objEstimate_t estimateType) : estimateType_(estimateType), estimateValue_(0.0) {}; ~SbbObjEstimate() {}; // / computes and returns the value of a specific objective function estimate double computeValue(SbbNode * node, SbbModel * model) { double increment; switch (estimateType_) { case ProE: {if (model->getObjValue() ==1.0e50) increment=(model->getContinuousObjective())/model->getContinuousSumInfeasibilities(); else increment=(model->getObjValue()-model->getContinuousObjective())/model->getContinuousSumInfeasibilities(); estimateValue_=node->objectiveValue()+(increment*node->estimates()[sumUnsatisfied]); break; } case ProNumE: {if (model->getObjValue() ==1.0e50) increment=(model->getContinuousObjective())/model->getContinuousInfeasibilitiesMod(); else increment=(model->getObjValue()-model->getContinuousObjective())/model->getContinuousInfeasibilitiesMod(); estimateValue_=node->objectiveValue()+(increment*node->estimates()[numUnsatisfiedMod]); break; } case PseudoE: {estimateValue_=0.0; break; } case DiffPseudoAverE: {estimateValue_=0.0; break; } case DiffPseudoMinE: {estimateValue_=0.0; break; } case DiffPseudoMaxE: {estimateValue_=0.0; break; } } return estimateValue_; } }; // ProE class SbbCompareProE : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareProE(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareProE() {}; // This returns true if the best prokection estimate for y is less than the best projection estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(ProE); return objEstimate.computeValue(x, model_) > objEstimate.computeValue(y, model_); } }; // ProNumE class SbbCompareProNumE : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareProNumE(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareProNumE() {}; // This returns true if the best prokection estimate adapted for the sum of integer infeasibilities for y is less than the best projection estimate adapted for the sum of integer infeasibilities of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(ProNumE); return objEstimate.computeValue(x, model_) > objEstimate.computeValue(y, model_); } }; // PseudoE class SbbComparePseudoE : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbComparePseudoE(SbbModel * model) : model_(model) {test_=this;}; ~SbbComparePseudoE() {}; // This returns true if the pseudocost estimate for y is less than the pseudocost estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(PseudoE); return objEstimate.computeValue(x, model_) > objEstimate.computeValue(y, model_); } }; // DiffPseudoAverE class SbbCompareDiffPseudoAverE: public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareDiffPseudoAverE(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareDiffPseudoAverE() {}; // This returns true if the pseudocost estimate altered for the average cost of variable fixings for y is less than the pseudocost estimate altered for the average cost of variable fixings of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(DiffPseudoAverE); return objEstimate.computeValue(x, model_) > objEstimate.computeValue(y, model_); } }; // DiffPseudoMinE class SbbCompareDiffPseudoMinE: public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareDiffPseudoMinE(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareDiffPseudoMinE() {}; // This returns true if the pseudocost estimate altered for the cost of variable fixings for y is less than the pseudocost estimate altered for the cost of variable fixings of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(DiffPseudoMinE); return objEstimate.computeValue(x, model_) > objEstimate.computeValue(y, model_); } }; // DiffPseudoMaxE class SbbCompareDiffPseudoMaxE: public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareDiffPseudoMaxE(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareDiffPseudoMaxE() {}; // This returns true if the pseudocost estimate altered for the maximum cost of variable fixings for y is less than the pseudocost estimate altered for the maximum cost of variable fixings of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(DiffPseudoMaxE); return objEstimate.computeValue(x, model_) > objEstimate.computeValue(y, model_); } }; // NormE class SbbCompareNormE : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareNormE(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareNormE() {}; // This returns true if the norm estimate for y is more than the morm estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(model_->getObjEstimateForNorm()); double denominatorForX=CoinAbs(objEstimate.computeValue(x, model_)-model_->getContinuousObjective()); double normEForX, normEForY; if (denominatorForX!=0.0) { normEForX=( x->depth()*x->depth())/ denominatorForX; } else { normEForX=( y->depth()*y->depth()) ; } double denominatorForY=CoinAbs(objEstimate.computeValue(y, model_)-model_->getContinuousObjective()); if (denominatorForY!=0.0) { normEForY=( y->depth()*y->depth())/ denominatorForY; } else { normEForY=( y->depth()*y->depth()) ; } return normEForX < normEForY; } }; // Norm2E class SbbCompareNorm2E : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareNorm2E(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareNorm2E() {}; // This returns true if the norm 2 estimate for y is more than the morm 2 estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(model_->getObjEstimateForNorm()); double denominatorForX=CoinAbs(objEstimate.computeValue(x, model_)-model_->getContinuousObjective()); double norm2EForX, norm2EForY; if (denominatorForX!=0.0) { norm2EForX=x->depth() / denominatorForX; } else { norm2EForX=x->depth() ; } double denominatorForY=CoinAbs(objEstimate.computeValue(y, model_)-model_->getContinuousObjective()); if (denominatorForY!=0.0) { norm2EForY= y->depth()/ denominatorForY; } else { norm2EForY=y->depth(); } return norm2EForX < norm2EForY; } }; // Norm3E class SbbCompareNorm3E : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareNorm3E(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareNorm3E() {}; // This returns true if the norm 3 estimate for y is more than the morm 3 estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(model_->getObjEstimateForNorm()); double norm3EForX, norm3EForY; double denominatorForX=x->estimates()[numUnsatisfiedMod]*CoinAbs(objEstimate.computeValue(x, model_)-model_->getContinuousObjective()); if (denominatorForX!=0.0) { norm3EForX=x->depth() / denominatorForX; } else { norm3EForX=x->depth() ; } double denominatorForY=y->estimates()[numUnsatisfiedMod]*CoinAbs(objEstimate.computeValue(y, model_)-model_->getContinuousObjective()); if (denominatorForY!=0.0) { norm3EForY= y->depth()/ denominatorForY; } else { norm3EForY=y->depth(); } return norm3EForX < norm3EForY; } }; // AltNorm class SbbCompareAltNormE : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareAltNormE(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareAltNormE() {}; // This returns true if the AltNorm estimate for y is more than the AltNorm estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(model_->getObjEstimateForNorm()); double numeratorForX, numeratorForY, altNormEForX, altNormEForY; if (model_->getObjValue() ==1.0e50) {numeratorForX=x->objectiveValue(); numeratorForY=y->objectiveValue(); } else { numeratorForX= model_->getObjValue() -x->objectiveValue(); numeratorForY= model_->getObjValue() -y->objectiveValue(); } double denominatorForX= CoinAbs(objEstimate.computeValue(x, model_)-model_->getContinuousObjective()); if (denominatorForX!=0.0) { altNormEForX= numeratorForX/ denominatorForX; } else { altNormEForX= numeratorForX; } double denominatorForY= CoinAbs(objEstimate.computeValue(y, model_)-model_->getContinuousObjective()); if (denominatorForY!=0.0) { altNormEForY= numeratorForY/denominatorForY; } else { altNormEForY=numeratorForY; } return altNormEForX < altNormEForY; } }; // AltNorm2 class SbbCompareAltNorm2E : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareAltNorm2E(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareAltNorm2E() {}; // This returns true if the AltNorm2 estimate for y is more than the AltNorm2 estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(model_->getObjEstimateForNorm()); double numeratorForX, numeratorForY, altNorm2EForX, altNorm2EForY; numeratorForX=x->objectiveValue(); numeratorForY=y->objectiveValue(); double denominatorForX= CoinAbs(objEstimate.computeValue(x, model_)-x->objectiveValue()); if (denominatorForX!=0.0) {altNorm2EForX= numeratorForX/ denominatorForX; } else { altNorm2EForX= numeratorForX; } double denominatorForY= CoinAbs(objEstimate.computeValue(y, model_)-y->objectiveValue()); if (denominatorForY!=0.0) { altNorm2EForY= numeratorForY/denominatorForY; } else { altNorm2EForY=numeratorForY; } return altNorm2EForX < altNorm2EForY; } }; // AltNorm3 class SbbCompareAltNorm3E : public SbbCompareBase{ public: SbbModel * model_; // Default Constructor SbbCompareAltNorm3E(SbbModel * model) : model_(model) {test_=this;}; ~SbbCompareAltNorm3E() {}; // This returns true if the AltNorm3 estimate for y is more than the AltNorm3 estimate of x virtual bool test (SbbNode * x, SbbNode * y) { SbbObjEstimate objEstimate(model_->getObjEstimateForNorm()); double numeratorForX, numeratorForY, altNorm3EForX, altNorm3EForY; if (model_->getObjValue() ==1.0e50) {numeratorForX=x->objectiveValue(); numeratorForY=y->objectiveValue(); } else { numeratorForX= model_->getObjValue() -x->objectiveValue(); numeratorForY= model_->getObjValue() -y->objectiveValue(); } double denominatorForX= CoinAbs(objEstimate.computeValue(x, model_)- x->objectiveValue()); if (denominatorForX!=0.0) { altNorm3EForX= numeratorForX/ denominatorForX; } else { altNorm3EForX= numeratorForX; } double denominatorForY= CoinAbs(objEstimate.computeValue(y, model_)-y->objectiveValue()); if (denominatorForY!=0.0) { altNorm3EForY= numeratorForY/denominatorForY; } else { altNorm3EForY=numeratorForY; } return altNorm3EForX < altNorm3EForY; } }; /* Before first solution do sumUnstisfied (givin equalitty, depth first), then it is computed to hit first solution more 2% */ class SbbCompareUserSumUnsatisfied : public SbbCompareBase { public: // Weight for each infeasibility double weight_; // num of solutions int numberSolutions_; // Default Constructor SbbCompareUserSumUnsatisfied() : weight_(-1.0), numberSolutions_(0) {test_=this;}; ~SbbCompareUserSumUnsatisfied() {}; /* Return true if y better than x Node y is better than node x if y has fewer unsatisfied (greater depth on tie) or after solution weighted value of y is more than weighted value of x */ virtual bool test (SbbNode * x, SbbNode * y) { if (weight_<0.0) { // before solution /* printf("x %d %d %g, y %d %d %g\n", x->numberUnsatisfied(),x->depth(),x->objectiveValue(), y->numberUnsatisfied(),y->depth(),y->objectiveValue()); */ if (x->estimates()[sumUnsatisfied] > y->estimates()[sumUnsatisfied]) return true; else if (x->estimates()[sumUnsatisfied] < y->estimates()[sumUnsatisfied]) return false; else return x->depth() < y->depth(); } else { // after solution return x->objectiveValue()+ weight_*x->numberUnsatisfied() > y->objectiveValue() + weight_*y->numberUnsatisfied(); } } // This allows method to change behavior as it is called // after each solution virtual void newSolution(SbbModel * model, double objectiveAtContinuous, int numberInfeasibilitiesAtContinuous) { if (model->getSolutionCount()==model->getNumberHeuristicSolutions()) return; // solution was got by rounding // set to get close to this solution double costPerInteger = (model->getObjValue()-objectiveAtContinuous)/ ((double) numberInfeasibilitiesAtContinuous); weight_ = 0.98*costPerInteger; numberSolutions_++; if (numberSolutions_>5) weight_ =0.0; // this searches on objective } // This allows method to change behavior virtual void every1000Nodes(SbbModel * model, int numberNodes) { if (numberNodes>10000) weight_ =0.0; // this searches on objective } }; //ADDG /* Before first solution do depth first, then it is computed to hit first solution more 2% */ class SbbCompareUser : public SbbCompareBase { public: // Weight for each infeasibility double weight_; // Number of solutions int numberSolutions_; // Default Constructor SbbCompareUser () : weight_(-1.0), numberSolutions_(0) {test_=this;}; ~SbbCompareUser() {}; /* Return true if y better than x Node y is better than node x if y has fewer unsatisfied (greater depth on tie) or after solution weighted value of y is more than weighted value of x */ virtual bool test (SbbNode * x, SbbNode * y) { if (weight_<0.0) { // before solution /* printf("x %d %d %g, y %d %d %g\n", x->numberUnsatisfied(),x->depth(),x->objectiveValue(), y->numberUnsatisfied(),y->depth(),y->objectiveValue()); */ if (x->numberUnsatisfied() > y->numberUnsatisfied()) return true; else if (x->numberUnsatisfied() < y->numberUnsatisfied()) return false; else return x->depth() < y->depth(); } else { // after solution return x->objectiveValue()+ weight_*x->numberUnsatisfied() > y->objectiveValue() + weight_*y->numberUnsatisfied(); } } // This allows method to change behavior as it is called // after each solution virtual void newSolution(SbbModel * model, double objectiveAtContinuous, int numberInfeasibilitiesAtContinuous) { if (model->getSolutionCount()==model->getNumberHeuristicSolutions()) return; // solution was got by rounding // set to get close to this solution double costPerInteger = (model->getObjValue()-objectiveAtContinuous)/ ((double) numberInfeasibilitiesAtContinuous); weight_ = 0.98*costPerInteger; numberSolutions_++; if (numberSolutions_>5) weight_ =0.0; // this searches on objective } // This allows method to change behavior virtual void every1000Nodes(SbbModel * model, int numberNodes) { if (numberNodes>10000) weight_ =0.0; // this searches on objective } }; #endif