Commit 7c43b973 authored by Simon de Givry's avatar Simon de Givry Committed by Thomas Schiex
Browse files

[option] -qpmult=[double] multiplier quadratic terms (default value is 2.0,...

[option] -qpmult=[double] multiplier quadratic terms (default value is 2.0, use 0.5 insteas for QPLIB instances) ; output QPBO solution found objective value in their original format
parent d786dcb8
......@@ -5,10 +5,9 @@ The goal is to minimize or maximize the quadratic function:
X' * W * X = \sum_i=1 to N \sum_j=1 to N W_ij * X_i * X_j
where W is a symmetric squared N*N matrix expressed by all its non-zero half (i<=j) squared matrix coefficients, X is a vector of N binary variables with domain values in {0,1} or {1,-1}, and X' is the transposed vector of X.
Note: for two indices i != j, coefficient W_ij = W_ji (symmetric matrix) and appears twice in the previous sum.
where W is a symmetric squared N*N matrix expressed by all its non-zero triangle (i<=j) matrix coefficients, X is a vector of N binary variables with domain values in {0,1} or {1,-1}, and X' is the transposed vector of X.
Note: for two indices i < j, quadratic coefficient term W_ji = W_ij (symmetric matrix) and appears twice in the previous sum. W_ij is therefore multiplied by two from the original file.
Note: coefficients can be positive or negative and are real float numbers. they are converted to fixed-point real numbers by multiplying them by 10^precision (see option -precision to modify it, default value is 7). Infinite coefficients are forbidden.
Note: depending on the sign of the number of variables in the first text line, the domain of all variables is either {0,1} or {1, -1}
......@@ -35,4 +34,4 @@ such that i <= j and W_ij != 0
--- suggestions send to:
simon.de-givry@inra.fr
INRA @ 2012
INRA @ 2018
// Cmake generated version
#define Toulbar_VERSION "1.0.0-123-g75f2763-master-tainted (1540908133)"
#define Toulbar_VERSION "1.0.0-124-ga60cca5-master-tainted (1541602277)"
......@@ -443,6 +443,7 @@ public:
static LcLevelType LcLevel;
static bool wcnf;
static bool qpbo;
static double qpboQuadraticCoefMultiplier;
static char* varOrder;
static int btdMode;
......@@ -527,7 +528,7 @@ inline bool CSP(Cost lb, Cost ub) { return CUT(lb + UNIT_COST, ub); }
#ifdef LONGLONG_COST
inline Cost rounding(Cost lb)
{
return (((lb % max(UNIT_COST, (Cost)floor(ToulBar2::costMultiplier))) != MIN_COST) ? (lb + (Cost)floor(ToulBar2::costMultiplier)) : lb);
return (((lb % max(UNIT_COST, (Cost)floor(fabs(ToulBar2::costMultiplier)))) != MIN_COST) ? (lb + (Cost)floor(fabs(ToulBar2::costMultiplier))) : lb);
}
inline bool CUT(Cost lb, Cost ub)
{
......
......@@ -144,6 +144,7 @@ Cost ToulBar2::deltaUb;
BEP* ToulBar2::bep;
bool ToulBar2::wcnf;
bool ToulBar2::qpbo;
double ToulBar2::qpboQuadraticCoefMultiplier;
char* ToulBar2::varOrder;
int ToulBar2::btdMode;
......@@ -303,6 +304,7 @@ void tb2init()
ToulBar2::bep = NULL;
ToulBar2::wcnf = false;
ToulBar2::qpbo = false;
ToulBar2::qpboQuadraticCoefMultiplier = 2.;
ToulBar2::varOrder = NULL;
ToulBar2::btdMode = 0;
......@@ -370,13 +372,8 @@ void tb2init()
}
/// \brief checks compatibility between selected options of ToulBar2 needed by numberjack/toulbar2
void tb2checkOptions(Cost ub)
void tb2checkOptions()
{
if (ub <= MIN_COST) {
cerr << "Error: wrong initial primal bound (negative or zero)." << endl;
exit(1);
}
if (ToulBar2::costMultiplier != UNIT_COST && (ToulBar2::uai || ToulBar2::qpbo)) {
cerr << "Error: cost multiplier cannot be used with UAI and QPBO formats. Use option -precision instead." << endl;
exit(1);
......@@ -412,14 +409,6 @@ void tb2checkOptions(Cost ub)
cerr << "Error: BTD search mode required for approximate solution counting (use '-B=1')." << endl;
exit(1);
}
if (ToulBar2::allSolutions && ToulBar2::btdMode == 1 && ub > 1) {
cerr << "Error: Solution enumeration by BTD-like search methods is only possible for feasability (use -ub=1 and integer costs only)." << endl;
exit(1);
}
if (ToulBar2::allSolutions && ToulBar2::btdMode == 1 && ub == 1 && ToulBar2::hbfs) {
cerr << "Error: Hybrid best-first search cannot currently look for all solutions when BTD mode is activated. Shift to DFS (use -hbfs:)." << endl;
exit(1);
}
if (ToulBar2::allSolutions && ToulBar2::btdMode > 1) {
cerr << "Error: RDS-like method cannot currently enumerate solutions. Use DFS/HBFS search or BTD (feasibility only)." << endl;
exit(1);
......@@ -1954,8 +1943,12 @@ void WCSP::preprocessing()
setDACOrder(elimorder);
processTernary();
propagate();
if (ToulBar2::verbose >= 0 && getLb() > previouslb)
cout << "PIC dual bound: " << getLb() << " (+" << 100. * (getLb() - previouslb) / getLb() << "%, " << numberOfConstraints() << " cost functions)" << endl;
if (ToulBar2::verbose >= 0 && getLb() > previouslb) {
if (ToulBar2::uai)
cout << "PIC dual bound: " << std::fixed << std::setprecision(ToulBar2::decimalPoint) << getDDualBound() << std::setprecision(DECIMAL_POINT) << " energy: " << -(Cost2LogProb(getLb()) + ToulBar2::markov_log) << " (+" << 100. * (getLb() - previouslb) / getLb() << "%, " << numberOfConstraints() << " cost functions)" << endl;
else
cout << "PIC dual bound: " << std::fixed << std::setprecision(ToulBar2::decimalPoint) << getDDualBound() << std::setprecision(DECIMAL_POINT) << " (+" << 100. * (getLb() - previouslb) / getLb() << "%, " << numberOfConstraints() << " cost functions)" << endl;
}
} while (getLb() > previouslb && 100. * (getLb() - previouslb) / getLb() > 0.5);
} else if (ToulBar2::preprocessNary > 0) {
processTernary();
......
......@@ -1465,7 +1465,18 @@ pair<Cost, Cost> Solver::hybridSolve(Cluster* cluster, Cost clb, Cost cub)
Cost Solver::beginSolve(Cost ub)
{
// Last-minute compatibility checks for ToulBar2 selected options
tb2checkOptions(wcsp->getUb());
if (ub <= MIN_COST) {
cerr << "Error: wrong initial primal bound (negative or zero)." << endl;
exit(1);
}
if (ToulBar2::allSolutions && ToulBar2::btdMode == 1 && ub > 1) {
cerr << "Error: Solution enumeration by BTD-like search methods is only possible for feasability (use -ub=1 and integer costs only)." << endl;
exit(1);
}
if (ToulBar2::allSolutions && ToulBar2::btdMode == 1 && ub == 1 && ToulBar2::hbfs) {
cerr << "Error: Hybrid best-first search cannot currently look for all solutions when BTD mode is activated. Shift to DFS (use -hbfs:)." << endl;
exit(1);
}
if (ToulBar2::searchMethod != DFBB) {
if (!ToulBar2::lds || ToulBar2::vnsLDSmax < 0)
......@@ -1476,8 +1487,8 @@ Cost Solver::beginSolve(Cost ub)
ToulBar2::vnsKmax = wcsp->numberOfUnassignedVariables();
}
if (wcsp->isGlobal() && ToulBar2::btdMode >= 1) {
cout << "Warning! Cannot use BTD-like search methods with global cost functions." << endl;
ToulBar2::btdMode = 0;
cout << "Error: cannot use BTD-like search methods with monolithic global cost functions (remove -B option)." << endl;
exit(1);
}
if (wcsp->isGlobal() && (ToulBar2::elimDegree_preprocessing >= 1 || ToulBar2::elimDegree_preprocessing < -1)) {
cout << "Warning! Cannot use generic variable elimination with global cost functions." << endl;
......
......@@ -127,6 +127,7 @@ enum {
OPT_treedec_ext,
OPT_clusterdec_ext,
OPT_qpbo_mult,
// search option
OPT_SEARCH_METHOD,
OPT_btdRootCluster,
......@@ -298,6 +299,7 @@ CSimpleOpt::SOption g_rgOptions[] = {
{ OPT_treedec_ext, (char*)"--treedec_ext", SO_REQ_SEP },
{ OPT_clusterdec_ext, (char*)"--clusterdec_ext", SO_REQ_SEP },
{ OPT_qpbo_mult, (char*)"-qpmult", SO_REQ_SEP },
{ OPT_SEARCH_METHOD, (char*)"-B", SO_REQ_SEP }, // -B [0,1,2] search method
{ OPT_SEARCH_METHOD, (char*)"--search", SO_REQ_SEP },
{ OPT_btdRootCluster, (char*)"-R", SO_REQ_SEP }, // root cluster used in BTD
......@@ -598,7 +600,7 @@ void help_msg(char* toulbar2filename)
#endif
cout << " *.wcnf : Weighted Partial Max-SAT format (see Max-SAT Evaluation)" << endl;
cout << " *.cnf : (Max-)SAT format" << endl;
cout << " *.qpbo : quadratic pseudo-Boolean optimization (unconstrained quadratic programming) format" << endl;
cout << " *.qpbo : quadratic pseudo-Boolean optimization (unconstrained quadratic programming) format (see also option -qpmult)" << endl;
#ifdef XMLFLAG
cout << " *.xml : CSP and weighted CSP in XML format XCSP 2.1";
#ifdef MAXCSP
......@@ -631,6 +633,7 @@ void help_msg(char* toulbar2filename)
#ifndef MENDELSOFT
cout << " -w=[filename] : writes last/all solutions in filename (or \"sol\" if no parameter is given)" << endl;
cout << " -precision=[integer] defines the number of digits that should be representable on probabilities in uai/pre files (default value is " << ToulBar2::resolution << ")" << endl;
cout << " -qpmult=[double] defines coefficient multiplier for quadratic terms (default value is " << ToulBar2::qpboQuadraticCoefMultiplier << ")" << endl;
#else
cout << " -w=[mode] : writes last solution found" << endl;
cout << " mode=0: saves pedigree with erroneous genotypings removed" << endl;
......@@ -1396,6 +1399,12 @@ int _tmain(int argc, TCHAR* argv[])
ToulBar2::costMultiplier = co;
}
if (args.OptionId() == OPT_qpbo_mult) {
double co = atof(args.OptionArg());
if (co != 0.)
ToulBar2::qpboQuadraticCoefMultiplier = co;
}
if (args.OptionId() == OPT_singletonConsistency)
ToulBar2::singletonConsistency = true;
if (args.OptionId() == OPT_vacValueHeuristic)
......@@ -2178,13 +2187,17 @@ int _tmain(int argc, TCHAR* argv[])
ToulBar2::incop_cmd.replace(2, 1, sseed);
}
tb2checkOptions();
try {
if (randomproblem)
solver->read_random(n, m, p, ToulBar2::seed, forceSubModular, randomglobal);
else
globalUb = solver->read_wcsp((char*)strfile.c_str());
if (globalUb <= MIN_COST) {
cerr << "Error: wrong initial primal bound (negative or zero)." << endl;
exit(1);
}
tb2checkOptions(globalUb);
//TODO: If --show_options then dump ToulBar2 object here
if (certificate) {
......
......@@ -530,8 +530,7 @@ public:
/// \brief initialization of ToulBar2 global variables (needed by numberjack/toulbar2)
extern void tb2init();
/// \brief checks compatibility between selected options of ToulBar2 (needed by numberjack/toulbar2)
/// \return new initial upper bound (if options assume it is a satisfaction problem instead of optimization)
extern void tb2checkOptions(Cost initialUpperBound);
extern void tb2checkOptions();
#endif /*TOULBAR2LIB_HPP_*/
/* Local Variables: */
......
......@@ -3263,11 +3263,11 @@ void WCSP::read_wcnf(const char* fileName)
}
/// \brief minimizes/maximizes \f$ X^t \times W \times X = \sum_{i=1}^N \sum_{j=1}^N W_{ij} \times X_i \times X_j \f$
/// where W is expressed by its M non-zero half squared matrix costs (can be positive or negative float numbers)
/// \note Costs for \f$ i \neq j \f$ are multiplied by 2 by this method (symmetric N*N squared matrix)
/// where W is expressed by its M non-zero triangle matrix terms (W_ij, i<=j, it can be positive or negative float numbers)
/// \note Quadratic terms for \f$ i < j \f$ are multiplied by 2 (see option -qpmult to change this value) to get a symmetric N*N squared matrix
/// \note If N is positive, then variable domain values are {0,1}
/// \note If N is negative, then variable domain values are {1,-1} with value 1 having index 0 and value -1 having index 1 in the output solutions
/// \note If M is positive then minimizes the quadratic function, else maximizes it
/// \note If M is positive then minimizes the quadratic objective function, else maximizes it
/// \warning It does not allow infinite costs (no forbidden assignments)
void WCSP::read_qpbo(const char* fileName)
{
......@@ -3340,6 +3340,8 @@ void WCSP::read_qpbo(const char* fileName)
sumcost += 2. * abs(cost[e]);
}
Double multiplier = Exp10((Double)ToulBar2::resolution);
ToulBar2::costMultiplier = multiplier;
if (!minimize) ToulBar2::costMultiplier *= -1.0;
if (multiplier * sumcost >= (Double)MAX_COST) {
cerr << "This resolution cannot be ensured on the data type used to represent costs! (see option -precision)" << endl;
exit(EXIT_FAILURE);
......@@ -3353,37 +3355,43 @@ void WCSP::read_qpbo(const char* fileName)
if (booldom) {
if (cost[e] > 0) {
if (minimize) {
costs[3] = (Cost)(multiplier * 2. * cost[e]);
costs[3] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * cost[e]);
} else {
costs[0] = (Cost)(multiplier * 2. * cost[e]);
costs[0] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * cost[e]);
costs[1] = costs[0];
costs[2] = costs[0];
negCost += costs[0];
}
} else {
if (minimize) {
costs[0] = (Cost)(multiplier * -2. * cost[e]);
costs[0] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * -cost[e]);
costs[1] = costs[0];
costs[2] = costs[0];
negCost += costs[0];
} else {
costs[3] = (Cost)(multiplier * -2. * cost[e]);
costs[3] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * -cost[e]);
}
}
} else {
if (cost[e] > 0) {
if (minimize) {
costs[0] = (Cost)(multiplier * 2. * cost[e]);
costs[0] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * 2. * cost[e]);
costs[3] = costs[0];
negCost += (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * cost[e]);
} else {
costs[1] = (Cost)(multiplier * 2. * cost[e]);
costs[1] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * 2. * cost[e]);
costs[2] = costs[1];
negCost += (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * cost[e]);
}
} else {
if (minimize) {
costs[1] = (Cost)(multiplier * -2. * cost[e]);
costs[1] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * -2. * cost[e]);
costs[2] = costs[1];
negCost += (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * -cost[e]);
} else {
costs[0] = (Cost)(multiplier * -2. * cost[e]);
costs[0] = (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * -2. * cost[e]);
costs[3] = costs[0];
negCost += (Cost)(multiplier * ToulBar2::qpboQuadraticCoefMultiplier * -cost[e]);
}
}
}
......@@ -3395,10 +3403,12 @@ void WCSP::read_qpbo(const char* fileName)
unaryCosts1[posx[e] - 1] += (Cost)(multiplier * cost[e]);
} else {
unaryCosts0[posx[e] - 1] += (Cost)(multiplier * cost[e]);
negCost += (Cost)(multiplier * cost[e]);
}
} else {
if (minimize) {
unaryCosts0[posx[e] - 1] += (Cost)(multiplier * -cost[e]);
negCost += (Cost)(multiplier * -cost[e]);
} else {
unaryCosts1[posx[e] - 1] += (Cost)(multiplier * -cost[e]);
}
......@@ -3406,15 +3416,19 @@ void WCSP::read_qpbo(const char* fileName)
} else {
if (cost[e] > 0) {
if (minimize) {
unaryCosts0[posx[e] - 1] += (Cost)(multiplier * cost[e]);
unaryCosts0[posx[e] - 1] += (Cost)(multiplier * 2. * cost[e]);
negCost += (Cost)(multiplier * cost[e]);
} else {
unaryCosts1[posx[e] - 1] += (Cost)(multiplier * cost[e]);
unaryCosts1[posx[e] - 1] += (Cost)(multiplier * 2. * cost[e]);
negCost += (Cost)(multiplier * cost[e]);
}
} else {
if (minimize) {
unaryCosts1[posx[e] - 1] += (Cost)(multiplier * -cost[e]);
unaryCosts1[posx[e] - 1] += (Cost)(multiplier * -2. * cost[e]);
negCost += (Cost)(multiplier * -cost[e]);
} else {
unaryCosts0[posx[e] - 1] += (Cost)(multiplier * -cost[e]);
unaryCosts0[posx[e] - 1] += (Cost)(multiplier * -2. * cost[e]);
negCost += (Cost)(multiplier * -cost[e]);
}
}
}
......@@ -3431,8 +3445,9 @@ void WCSP::read_qpbo(const char* fileName)
}
}
sortConstraints();
if (ToulBar2::verbose >= 0)
cout << "Read " << n << " variables, with " << 2 << " values at most, and " << m << " nonzero matrix costs." << endl;
if (ToulBar2::verbose >= 0) {
cout << "Read " << n << " variables, with " << 2 << " values at most, and " << m << " nonzero matrix costs (quadratic coef. multiplier: " << ToulBar2::qpboQuadraticCoefMultiplier << ", shifting value: " << -negCost << ")" << endl;
}
}
/* Local Variables: */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment