/** scale the cut passed as argument*/ void scale(OsiRowCut &cut) { double rhs = fabs(cut.lb()); CoinPackedVector row; row.reserve(cut.row().getNumElements()); for (int i = 0 ; i < cut.row().getNumElements() ; i++) { row.insert(cut.row().getIndices()[i], cut.row().getElements()[i]/rhs); } cut.setLb(cut.lb()/rhs); cut.setRow(row); }
/** scale the cut passed as argument using provided normalization factor*/ void scale(OsiRowCut &cut, double norma) { assert(norma >0.); CoinPackedVector row; row.reserve(cut.row().getNumElements()); for (int i = 0 ; i < cut.row().getNumElements() ; i++) { row.insert(cut.row().getIndices()[i], cut.row().getElements()[i]/norma); } cut.setLb(cut.lb()/norma); cut.setRow(row); }
//@{ template <class BinaryFunction> void binaryOp(CoinPackedVector& retVal, const CoinPackedVectorBase& op1, double value, BinaryFunction bf) { retVal.clear(); const int s = op1.getNumElements(); if (s > 0) { retVal.reserve(s); const int * inds = op1.getIndices(); const double * elems = op1.getElements(); for (int i=0; i<s; ++i ) { retVal.insert(inds[i], bf(value, elems[i])); } } }
template <class BinaryFunction> void binaryOp(CoinPackedVector& retVal, const CoinPackedVectorBase& op1, const CoinPackedVectorBase& op2, BinaryFunction bf) { retVal.clear(); const int s1 = op1.getNumElements(); const int s2 = op2.getNumElements(); /* Replaced || with &&, in response to complaint from Sven deVries, who rightly points out || is not appropriate for additive operations. && should be ok as long as binaryOp is understood not to create something from nothing. -- lh, 04.06.11 */ if (s1 == 0 && s2 == 0) return; retVal.reserve(s1+s2); const int * inds1 = op1.getIndices(); const double * elems1 = op1.getElements(); const int * inds2 = op2.getIndices(); const double * elems2 = op2.getElements(); int i; // loop once for each element in op1 for ( i=0; i<s1; ++i ) { const int index = inds1[i]; const int pos2 = op2.findIndex(index); const double val = bf(elems1[i], pos2 == -1 ? 0.0 : elems2[pos2]); // if (val != 0.0) // *THINK* : should we put in only nonzeros? retVal.insert(index, val); } // loop once for each element in operand2 for ( i=0; i<s2; ++i ) { const int index = inds2[i]; // if index exists in op1, then element was processed in prior loop if ( op1.isExistingIndex(index) ) continue; // Index does not exist in op1, so the element value must be zero const double val = bf(0.0, elems2[i]); // if (val != 0.0) // *THINK* : should we put in only nonzeros? retVal.insert(index, val); } }
void exprQuad::quadCuts (expression *w, OsiCuts &cs, const CouenneCutGenerator *cg){ #ifdef DEBUG std::cout<<"Expression has "<< lcoeff_.size () <<" linear terms and " << nqterms_ <<" quadratic terms." << std::endl; printf ("Q:"); for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) { int xind = row -> first -> Index (); for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col) printf (" <%d,%d,%g>", xind, col -> first -> Index (), col -> second); } printf ("\nb:"); for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) //for (int i=0; i < nlterms_; i++) printf (" <%d,%g>", el -> first -> Index (), el -> second);//index_ [i], coeff_ [i]); if (c0_) printf ("; <c0 = %g>", c0_); printf ("\nBounds: var val lb ub eigval scaled\n"); int index = 0; for (std::map <exprVar *, std::pair <CouNumber, CouNumber> >::iterator i = bounds_.begin (); i != bounds_.end (); ++i, index++) { printf ("%3d:\t", index); i -> first -> print (); printf ("\t"); printf (" %8g [%8g, %8g]", (*(i -> first)) (), i -> second.first, i -> second.second); CouNumber lb = cg -> Problem () -> Lb (i -> first -> Index ()), ub = cg -> Problem () -> Ub (i -> first -> Index ()); if ((eigen_.size () > 0) && (fabs (ub-lb) > COUENNE_EPS)) printf (" --> %8g %8g", eigen_.begin () -> first, eigen_.begin () -> first / (ub-lb)); printf ("\n"); } #endif // Get on which side constraint is violated to get the good lambda CouNumber varVal = (*w) (), exprVal = (*this) (), lambda = (eigen_.size () == 0) ? 0. : (varVal < exprVal) ? CoinMin (0., eigen_.begin () -> first) : // Use under-estimator CoinMax (0., eigen_.rbegin () -> first), // Use over-estimator convVal = 0.; enum auxSign sign = cg -> Problem () -> Var (w -> Index ()) -> sign (); // if this is a "semi"-auxiliary, check if necessary to separate if ((sign == expression::AUX_GEQ && varVal > exprVal) || (sign == expression::AUX_LEQ && varVal < exprVal)) return; const CouenneProblem& problem = *(cg -> Problem ()); const int numcols = problem.nVars (); const double *colsol = problem.X (), // current solution *lower = problem.Lb (), // lower bound *upper = problem.Ub (); // upper // compute lower or upper convexification and check if it contains // the current point if (fabs (lambda) > COUENNE_EPS) { convVal = exprVal; // there is a convexification, check if out of current point for (std::map <exprVar *, std::pair <CouNumber, CouNumber> >::iterator i = bounds_.begin (); i != bounds_.end (); ++i) { int ind = i -> first -> Index (); CouNumber xi = colsol [ind], lb = lower [ind], ub = upper [ind], delta = ub-lb; if (fabs (delta) > COUENNE_EPS) convVal += lambda * (xi-lb) * (ub-xi) / (delta * delta); } if (varVal < exprVal) {if (convVal < varVal) return;} else {if (convVal > varVal) return;} } #ifdef DEBUG std::cout << "Point to cut: "; for (int i = 0 ; i < numcols ; i++) std::cout << colsol [i] << ", "; printf (" (w,f(x),c) = (%g,%g,%g) -- lambda = %g\n", (*w) (), exprVal, convVal, lambda); #endif // Initialize by copying $a$ into a dense vector and computing Q x^* double *Qxs = new double [numcols], // sparse coefficient vector, $Qx^*$ a0 = -c0_; // constant term CoinFillN (Qxs, numcols, 0.); // Compute 2 * Q x^*. for (sparseQ::iterator row = matrix_.begin (); row != matrix_.end (); ++row) { int qi = row -> first -> Index (); for (sparseQcol::iterator col = row -> second.begin (); col != row -> second.end (); ++col) { int qj = col -> first -> Index (); CouNumber qc = col -> second, xi = colsol [qi], xj = colsol [qj]; if (qi != qj) { Qxs [qi] += qc * xj; // contribution of element $q_{ij}$ to (Qx)_i Qxs [qj] += qc * xi; // $q_{ij}$ (Qx)_j a0 += 2 * qc * xi * xj; } else { /* if (fabs (lambda) > COUENNE_EPS) { CouNumber lb = lower [qi], ub = upper [qi], delta = ub-lb; if (fabs (delta) > COUENNE_EPS) qc -= lambda / (delta*delta); } */ // elements on the diagonal are not halved upon reading a0 += qc * xi * xi; Qxs [qi] += 2 * qc * xi; } } } #ifdef DEBUG printf ("2Qx = ("); for (int i = 0; i < numcols; i++) printf ("%g ", Qxs [i]); printf (")\n"); #endif // Add a to it. for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) Qxs [el -> first -> Index ()] += el -> second; //coeff_ [i]; // multiply Qx^* by x^*^T again and store the result for the lower // bound into constant term /* for (int i=0; i < numcols; i++){ a0 -= 0.5 * Qxs [i] * colsol [i]; // Qxs [i] *= 2; } */ // And myself Qxs [w -> Index ()] -= 1; #ifdef DEBUG printf ("2Qx = ("); for(int i = 0; i < numcols; i++) printf ("%g ", Qxs [i]); printf (")[%g]\n",a0); #endif //a0 -= exprVal; if (fabs (lambda) > COUENNE_EPS) // Now the part which depends on lambda, if there is one for (std::map <exprVar *, std::pair <CouNumber, CouNumber> >::iterator i = bounds_.begin (); i != bounds_.end (); ++i) { int ind = i -> first -> Index (); CouNumber xi = colsol [ind], lb = lower [ind], ub = upper [ind], delta = ub-lb; if (fabs (delta) > COUENNE_EPS) { CouNumber normlambda = lambda / (delta*delta), coeff = normlambda * (lb + ub - 2. * xi); a0 += normlambda * (lb*ub - xi*xi); //a0 += coeff * xi - normlambda * (xi - lb) * (ub - xi); //a0 += normlambda * lb * ub; Qxs [ind] += coeff; //Qxs [ind] += normlambda * (lb + ub); }// else coeff = 0.; // a0 += lambda [k] * lower [ind] * upper [ind]; // a0 -= lambda [k] * colsol [ind] * colsol [ind]; //Qxs [ind] -= lambda [k] * (colsol [ind]) * 2; } // Count the number of non-zeroes int nnz = 0; for (int i=0; i < numcols ; i++) if (fabs (Qxs [i]) > COUENNE_EPS) nnz++; #ifdef DEBUG printf ("2Qx = (");for(int i=0;i<numcols;i++)printf("%g ",Qxs[i]);printf (")[%g], %d nz\n",a0,nnz); #endif // Pack the vector into a CoinPackedVector and generate the cut. CoinPackedVector a (false); a.reserve (nnz); #ifdef DEBUG CouNumber lhs = 0, lhsc = 0, *optimum = cg -> Problem () -> bestSol (), *current = cg -> Problem () -> X (); #endif for (int i=0; i < numcols; i++) if (fabs (Qxs [i]) > 1.0e-21) { // why 1.0e-21? Look at CoinPackedMatrix.cpp:2188 // compute violation #ifdef DEBUG if (optimum) { printf ("%+g * %g ", Qxs [i], optimum [i]); lhs += Qxs [i] * optimum [i]; } lhsc += Qxs [i] * current [i]; #endif a.insert (i, Qxs [i]); } OsiRowCut cut; cut.setRow (a); delete [] Qxs; if (varVal < exprVal) { //(lambda == dCoeffLo_) { cut.setUb (a0); #ifdef DEBUG if (optimum && (lhs - a0 > COUENNE_EPS)) { printf ("cut violates optimal solution: %g > %g\n", lhs, a0); cut.print (); } if (lhsc < a0 + COUENNE_EPS){ printf ("cut (+) is not cutting: "); cut.print (); } #endif // cut.setLb(-COUENNE_INFINITY); } else { cut.setLb (a0); #ifdef DEBUG if (optimum && (lhs - a0 < -COUENNE_EPS)) { printf ("cut violates optimal solution: %g < %g\n", lhs, a0); cut.print (); } if (lhsc > a0 - COUENNE_EPS){ printf ("cut (-) is not cutting: "); cut.print (); } #endif // cut.setUb(COUENNE_INFINITY); } cs.insert (cut); }