调整线性规划获取属性的接口

This commit is contained in:
2025-05-16 17:39:10 +08:00
parent 6d3594c9ba
commit 0ae1785e6c
3 changed files with 311 additions and 47 deletions

View File

@ -5,6 +5,9 @@ using std::vector;
class Expr; class Expr;
class Var; class Var;
#define MDL_MINIMIZE 1
#define MDL_MAXIMIZE -1
Expr operator+(const Expr& x, const Expr& y); Expr operator+(const Expr& x, const Expr& y);
Expr operator-(const Expr& x, const Expr& y); Expr operator-(const Expr& x, const Expr& y);
Expr operator+(const Expr& x); Expr operator+(const Expr& x);
@ -25,7 +28,6 @@ Expr operator/(const Expr& x, double a);
typedef vector<vector<double>> Matrix; typedef vector<vector<double>> Matrix;
enum class Rtn { enum class Rtn {
LOADED, LOADED,
OPTIMAL, OPTIMAL,
@ -47,10 +49,212 @@ enum class Rtn {
PIVOT, PIVOT,
}; };
enum class IntAttr {
NumConstrs,
NumVars,
NumSOS,
NumQConstrs,
NumGenConstrs,
NumNZs,
NumQNZs,
NumQCNZs,
NumIntVars,
NumBinVars,
NumPWLObjVars,
ModelSense,
IsMIP,
IsQP,
IsQCP,
IsMultiObj,
Status,
ConcurrentWinMethod,
SolCount,
BarIterCount,
VBasis,
CBasis,
PWLObjCvx,
BranchPriority,
VarPreStat,
BoundVioIndex,
BoundSVioIndex,
ConstrVioIndex,
ConstrSVioIndex,
ConstrResidualIndex,
ConstrSResidualIndex,
DualVioIndex,
DualSVioIndex,
DualResidualIndex,
DualSResidualIndex,
ComplVioIndex,
IntVioIndex,
IISMinimal,
IISLB,
IISUB,
IISConstr,
IISSOS,
IISQConstr,
IISGenConstr,
IISLBForce,
IISUBForce,
IISConstrForce,
IISSOSForce,
IISQConstrForce,
IISGenConstrForce,
TuneResultCount,
Lazy,
VarHintPri,
ObjNPriority,
NumObj,
GenConstrType,
NumStart,
Partition,
LicenseExpiration,
NumScenarios,
FuncPieces,
BatchErrorCode,
BatchStatus,
Fingerprint,
PoolIgnore,
FuncNonlinear,
ModelColumn
};
enum class DoubleAttr{
Runtime,
Work,
ObjCon,
LB,
UB,
Obj,
Start,
PreFixVal,
RHS,
QCRHS,
Coeff,
MaxCoeff,
MinCoeff,
MaxBound,
MinBound,
MaxObjCoeff,
MinObjCoeff,
MaxRHS,
MinRHS,
MaxQCRHS,
MinQCRHS,
MaxQCCoeff,
MinQCCoeff,
MaxQCLCoeff,
MinQCLCoeff,
MaxQObjCoeff,
MinQObjCoeff,
ObjVal,
ObjBound,
ObjBoundC,
MIPGap,
IterCount,
NodeCount,
X,
RC,
Pi,
QCPi,
Slack,
QCSlack,
MaxVio,
BoundVio,
BoundSVio,
BoundVioSum,
BoundSVioSum,
ConstrVio,
ConstrSVio,
ConstrVioSum,
ConstrSVioSum,
ConstrResidual,
ConstrSResidual,
ConstrResidualSum,
ConstrSResidualSum,
DualVio,
DualSVio,
DualVioSum,
DualSVioSum,
DualResidual,
DualSResidual,
DualResidualSum,
DualSResidualSum,
ComplVio,
ComplVioSum,
IntVio,
IntVioSum,
Kappa,
KappaExact,
SAObjLow,
SAObjUp,
SALBLow,
SALBUp,
SARHSLow,
SAUBLow,
SAUBUp,
SARHSUp,
Xn,
FarkasProof,
FarkasDual,
UnbdRay,
PStart,
DStart,
BarX,
VarHintVal,
ObjN,
ObjNCon,
ObjNWeight,
ObjNRelTol,
ObjNAbsTol,
ObjNVal,
OpenNodeCount,
PoolObjBound,
PoolObjVal,
ScenNLB,
ScenNUB,
ScenNObj,
ScenNRHS,
ScenNX,
ScenNObjBound,
ScenNObjVal,
FuncPieceError,
FuncPieceLength,
FuncPieceRatio,
DNumNZs
};
enum class StringAttr {
ModelName,
VarName,
ConstrName,
QCName,
GenConstrName,
ObjNName,
ScenNName,
BatchID,
VTag,
CTag,
QCTag,
BatchErrorMessage
};
enum class ConstrOper {
LESS_EQUAL,
GREATER_EQUAL,
EQUAL
};
class Var { class Var {
public: public:
Var(double coef = 1) :col(0), coeffs(coef) {}; Var(double coef = 1) :col(0), val(0), coeffs(coef) {};
double get(DoubleAttr attr);
int get(IntAttr attr);
friend class Model;
friend class Expr;
private:
double coeffs; double coeffs;
double val;
int col; int col;
}; };
@ -101,18 +305,17 @@ class Model
public: public:
Model(); Model();
Var* addVars(int col); Var* addVars(int col);
void addConstr(const Expr& expr, char sense, double rhs); void addConstr(const Expr& expr, ConstrOper sense, double rhs);
void setObjective(Expr obje, int sense = 0); void setObjective(Expr obje, int sense = MDL_MAXIMIZE);
void print(); void print();
Rtn optimize(bool isMax = true); Rtn optimize();
double get(); double get(DoubleAttr attr);
int get(IntAttr attr);
private: private:
double _simplex(); double _simplex();
Rtn _pivot(std::pair<size_t, size_t>& p); Rtn _pivot(std::pair<size_t, size_t>& p);
void _gaussian(std::pair<size_t, size_t> p); void _gaussian(std::pair<size_t, size_t> p);
Var* vars; Var* vars;
Matrix matrix; Matrix matrix;
@ -120,4 +323,5 @@ private:
vector<int> basic; vector<int> basic;
Rtn rtn; Rtn rtn;
double res; double res;
int sense;
}; };

View File

@ -9,24 +9,26 @@ int main(int argc, char* argv[])
{ {
Model mdl; Model mdl;
Var* vars = mdl.addVars(3); Var* vars = mdl.addVars(2);
mdl.addConstr(vars[0] + vars[1] + vars[2], '<', 4); mdl.addConstr(vars[0] + vars[1], ConstrOper::LESS_EQUAL, 2);
mdl.addConstr(vars[0], '<', 2); mdl.addConstr(vars[0] + vars[1], ConstrOper::GREATER_EQUAL, 1);
mdl.addConstr(vars[2], '<', 3); mdl.addConstr(5 * vars[0] - 2 * vars[1], ConstrOper::GREATER_EQUAL, -2);
mdl.addConstr(3 * vars[1] + vars[2], '<', 6);
mdl.setObjective(vars[0] + 14 * vars[1] + 6 * vars[2]); mdl.setObjective(vars[0] + 2 * vars[1], MDL_MAXIMIZE);
switch(mdl.optimize(false)) { switch(mdl.optimize()) {
case Rtn::OPTIMAL: case Rtn::OPTIMAL:
cout << "find solution: " << mdl.get() << endl; cout << "OPTIMAL SOLUTION: " << mdl.get(DoubleAttr::Obj) << endl;
for (int i = 0; i < mdl.get(IntAttr::NumVars); i++) {
cout << "var[" << i << "] : " << vars[i].get(DoubleAttr::X) << endl;
}
break; break;
case Rtn::INFEASIBLE: case Rtn::INFEASIBLE:
cout << "no solution" << endl; cout << "INFEASIBLE MODEL" << endl;
break; break;
case Rtn::UNBOUNDED: case Rtn::UNBOUNDED:
cout << "unbounded solution" << endl; cout << "UNBOUNDED SOLUTION" << endl;
break; break;
default: default:
assert(false); assert(false);

View File

@ -32,16 +32,16 @@ Expr operator+(const Expr& x)
Expr operator+(Var x, Var y) Expr operator+(Var x, Var y)
{ {
Expr exp; Expr exp;
exp.coeffs.resize(std::max(x.col + 1, y.col + 1), 0); exp.coeffs.resize(std::max(x.get(IntAttr::ModelColumn) + 1, y.get(IntAttr::ModelColumn) + 1), 0);
exp.coeffs[x.col] = x.coeffs; exp.coeffs[x.get(IntAttr::ModelColumn)] = x.get(DoubleAttr::Coeff);
exp.coeffs[y.col] = y.coeffs; exp.coeffs[y.get(IntAttr::ModelColumn)] = y.get(DoubleAttr::Coeff);
return exp; return exp;
} }
Expr operator+(Var x, double a) Expr operator+(Var x, double a)
{ {
Expr exp; Expr exp;
exp.coeffs.resize(x.col + 1); exp.coeffs.resize(x.get(IntAttr::ModelColumn) + 1);
exp.constant = a; exp.constant = a;
return exp; return exp;
} }
@ -85,9 +85,9 @@ Expr operator-(Var x)
Expr operator-(Var x, Var y) Expr operator-(Var x, Var y)
{ {
Expr exp; Expr exp;
exp.coeffs.resize(std::max(x.col + 1, y.col + 1), 0); exp.coeffs.resize(std::max(x.get(IntAttr::ModelColumn) + 1, y.get(IntAttr::ModelColumn) + 1), 0);
exp.coeffs[x.col] = x.coeffs; exp.coeffs[x.get(IntAttr::ModelColumn)] = x.get(DoubleAttr::Coeff);
exp.coeffs[y.col] = -y.coeffs; exp.coeffs[y.get(IntAttr::ModelColumn)] = -y.get(DoubleAttr::Coeff);
return exp; return exp;
} }
@ -104,8 +104,8 @@ Expr operator-(double a, Var x)
Expr operator*(double a, Var x) Expr operator*(double a, Var x)
{ {
Expr exp; Expr exp;
exp.coeffs.resize(x.col + 1, 0); exp.coeffs.resize(x.get(IntAttr::ModelColumn) + 1, 0);
exp.coeffs[x.col] = a * x.coeffs; exp.coeffs[x.get(IntAttr::ModelColumn)] = a * x.get(DoubleAttr::Coeff);
return exp; return exp;
} }
@ -147,6 +147,7 @@ Expr operator/(const Expr& x, double a)
Model::Model(): Model::Model():
cn(0), cn(0),
bn(0), bn(0),
sense(0),
vars(nullptr) vars(nullptr)
{ {
@ -165,22 +166,50 @@ Var* Model::addVars(int num)
return vars; return vars;
} }
void Model::addConstr(const Expr& expr, char sense, double rhs) void Model::addConstr(const Expr& expr, ConstrOper sense, double rhs)
{ {
matrix.push_back(vector<double>(1, rhs)); // TODO<44><4F>û<EFBFBD>ȴ<EFBFBD>С<EFBFBD><D0A1>û<EFBFBD><C3BB><EFBFBD>dz<EFBFBD><C7B3><EFBFBD>
matrix.back().insert(matrix.back().end(), expr.coeffs.begin(), expr.coeffs.end()); if (sense == ConstrOper::LESS_EQUAL) {
matrix.push_back(vector<double>(1, rhs - expr.constant));
matrix.back().insert(matrix.back().end(), expr.coeffs.begin(), expr.coeffs.end());
}
else if (sense == ConstrOper::GREATER_EQUAL) {
matrix.push_back(vector<double>(1, expr.constant - rhs));
for (int coeff : expr.coeffs) {
matrix.back().push_back(-coeff);
}
}
else {
addConstr(expr, ConstrOper::LESS_EQUAL, rhs);
addConstr(expr, ConstrOper::GREATER_EQUAL, rhs);
}
for (int c = matrix.back().size(); c <= cn; c++) { for (int c = matrix.back().size(); c <= cn; c++) {
matrix.back().push_back(0); matrix.back().push_back(0);
} }
} }
void Model::setObjective(Expr obje, int sense) void Model::setObjective(Expr obje, int _sense)
{ {
matrix.insert(matrix.begin(), obje.coeffs); assert(_sense == 1 || _sense == -1);
matrix.front().insert(matrix.front().begin(), obje.constant); // TODO<44><4F>д<EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD> if (sense == 0) {
for (int c = matrix.front().size(); c <= cn; c++) { matrix.insert(matrix.begin(), obje.coeffs);
matrix.front().push_back(0); matrix.front().insert(matrix.front().begin(), -obje.constant);
for (int c = obje.coeffs.size() + 1; c <= cn; c++) {
matrix.front().push_back(0);
}
} }
else {
matrix.front().front() = -obje.constant;
for (int c = 0; c < obje.coeffs.size(); c++) {
matrix.front()[c + 1] = obje.coeffs[c];
}
for (int c = obje.coeffs.size() + 1; c <= cn; c++) {
matrix.front()[c] = 0;
}
}
sense = _sense;
} }
void Model::print() void Model::print()
@ -193,7 +222,7 @@ void Model::print()
} }
} }
Rtn Model::optimize(bool isMax) Rtn Model::optimize()
{ {
bn = matrix.size(); bn = matrix.size();
for (int row = 1; row < bn; row++) { for (int row = 1; row < bn; row++) {
@ -203,12 +232,10 @@ Rtn Model::optimize(bool isMax)
} }
} }
cn = matrix.front().size(); cn = matrix.front().size();
if (!isMax) { for (int i = 0; i < cn; i++) {
for (int i = 0; i < cn; i++) { matrix.front()[i] = sense * matrix.front()[i];
matrix.front()[i] = -matrix.front()[i];
}
} }
for (size_t i = 1; i < bn; i++) { for (size_t i = 1; i < bn; i++) {
basic.push_back(cn - bn + i); basic.push_back(cn - bn + i);
} }
@ -246,9 +273,9 @@ Rtn Model::optimize(bool isMax)
auto iter = find(basic.begin(), basic.end(), cn); auto iter = find(basic.begin(), basic.end(), cn);
if (iter != basic.end()) { if (iter != basic.end()) {
for (int col = 1; col < matrix.front().size(); col++) { for (int col = 1; col < matrix.front().size(); col++) {
if (matrix.front()[col] != 1) { if (fabs(matrix.front()[col]) > 1e-10) {
t = make_pair(iter - basic.begin(), col); t = make_pair(iter - basic.begin() + 1, col);
_pivot(t); _gaussian(t);
break; break;
} }
} }
@ -270,15 +297,25 @@ Rtn Model::optimize(bool isMax)
} }
} }
res = isMax ? _simplex() : _simplex(); res = -sense * _simplex();
for (int row = 1; row < bn; row++) {
if (basic[row - 1] - 1 < cn - bn) {
vars[basic[row - 1] - 1].val = matrix[row].front();
}
}
return rtn; return rtn;
} }
double Model::get() double Model::get(DoubleAttr attr)
{ {
return res; return res;
} }
int Model::get(IntAttr attr)
{
return cn - bn;
}
double Model::_simplex() double Model::_simplex()
{ {
pair<size_t, size_t> t; pair<size_t, size_t> t;
@ -289,7 +326,6 @@ double Model::_simplex()
} }
_gaussian(t); _gaussian(t);
} }
return matrix.front().front(); return matrix.front().front();
} }
@ -381,6 +417,7 @@ void Expr::operator+=(const Expr& expr)
for (int c = 0; c < expr.coeffs.size(); c++) { for (int c = 0; c < expr.coeffs.size(); c++) {
coeffs[c] += expr.coeffs[c]; coeffs[c] += expr.coeffs[c];
} }
constant += expr.constant;
} }
void Expr::operator-=(const Expr& expr) void Expr::operator-=(const Expr& expr)
@ -389,6 +426,7 @@ void Expr::operator-=(const Expr& expr)
for (int c = 0; c < expr.coeffs.size(); c++) { for (int c = 0; c < expr.coeffs.size(); c++) {
coeffs[c] -= expr.coeffs[c]; coeffs[c] -= expr.coeffs[c];
} }
constant -= expr.constant;
} }
void Expr::operator*=(double mult) void Expr::operator*=(double mult)
@ -396,6 +434,7 @@ void Expr::operator*=(double mult)
for (int c = 0; c < coeffs.size(); c++) { for (int c = 0; c < coeffs.size(); c++) {
coeffs[c] *= mult; coeffs[c] *= mult;
} }
constant *= mult;
} }
void Expr::operator/=(double a) void Expr::operator/=(double a)
@ -403,6 +442,7 @@ void Expr::operator/=(double a)
for (int c = 0; c < coeffs.size(); c++) { for (int c = 0; c < coeffs.size(); c++) {
coeffs[c] /= a; coeffs[c] /= a;
} }
constant /= a;
} }
Expr Expr::operator+(const Expr& rhs) Expr Expr::operator+(const Expr& rhs)
@ -411,6 +451,7 @@ Expr Expr::operator+(const Expr& rhs)
for (int c = 0; c < rhs.coeffs.size(); c++) { for (int c = 0; c < rhs.coeffs.size(); c++) {
coeffs[c] += rhs.coeffs[c]; coeffs[c] += rhs.coeffs[c];
} }
constant += rhs.constant;
return *this; return *this;
} }
@ -420,5 +461,22 @@ Expr Expr::operator-(const Expr& rhs)
for (int c = 0; c < rhs.coeffs.size(); c++) { for (int c = 0; c < rhs.coeffs.size(); c++) {
coeffs[c] -= rhs.coeffs[c]; coeffs[c] -= rhs.coeffs[c];
} }
constant -= rhs.constant;
return *this; return *this;
} }
double Var::get(DoubleAttr attr)
{
switch (attr) {
case DoubleAttr::Coeff:
return coeffs;
case DoubleAttr::X:
return val;
}
return val;
}
int Var::get(IntAttr attr)
{
return col;
}