调整表达式运算错误,重新排版代码,优化单纯形搜索过程
This commit is contained in:
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.16.0)
|
cmake_minimum_required(VERSION 3.16.0)
|
||||||
|
|
||||||
project(Solver)
|
project(solver)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
@@ -22,10 +22,10 @@ file(GLOB HEADERS "${INCLUDE_DIR}/*.hpp")
|
|||||||
aux_source_directory(${SOURCE_DIR} src)
|
aux_source_directory(${SOURCE_DIR} src)
|
||||||
aux_source_directory(${INCLUDE_DIR} inc)
|
aux_source_directory(${INCLUDE_DIR} inc)
|
||||||
|
|
||||||
add_executable(Solver ${SOURCES} ${HEADERS})
|
add_executable(solver ${SOURCES} ${HEADERS})
|
||||||
|
|
||||||
#target_link_libraries(Solver
|
#target_link_libraries(solver
|
||||||
# ${GUROBI_LIBRARIES}
|
# ${GUROBI_LIBRARIES}
|
||||||
#)
|
#)
|
||||||
|
|
||||||
target_include_directories(Solver PRIVATE ${SOURCE_DIR} ${INCLUDE_DIR})
|
target_include_directories(solver PRIVATE ${SOURCE_DIR} ${INCLUDE_DIR})
|
||||||
|
|||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
## P0 基础修复
|
||||||
|
|
||||||
|
1. 补齐变量约束能力:完善变量 LB/UB 上下界定义与校验;对 BINARY 类型严格强制 0-1 取值
|
||||||
|
2. 增加测试与回归用例:搭建基础测试基线,覆盖整数、二进制、简单 MIP 算例,建立回归机制
|
||||||
|
|
||||||
|
## P1 核心能力
|
||||||
|
|
||||||
|
3. 完善终止条件与工程可控性:实现 TimeLimit 时间限制、MIPGap 收敛间隙终止条件;完善运行日志输出
|
||||||
|
4. 迭代 MIP 分支与节点选择策略:按顺序落地:best-bound 选节点 → pseudocost 分支策略
|
||||||
|
|
||||||
|
## P2 进阶算法
|
||||||
|
|
||||||
|
5. 增加启发式、割平面与预处理能力:实现一种rounding舍入启发式、root层Gomory割平面、简单预处理逻辑
|
||||||
|
|
||||||
|
## P3 底层求解架构
|
||||||
|
|
||||||
|
6. 学习稀疏单纯形,对接HiGHS等成熟求解器架构:调研学习稀疏单纯形、稀疏基分解、对偶单纯形热启动机制
|
||||||
|
|
||||||
|
## P4 工程收口与标准化(待定)
|
||||||
+144
-152
@@ -4,171 +4,163 @@
|
|||||||
#define MDL_MINIMIZE 1
|
#define MDL_MINIMIZE 1
|
||||||
#define MDL_MAXIMIZE -1
|
#define MDL_MAXIMIZE -1
|
||||||
|
|
||||||
#define LOADED 0
|
#define LOADED 0
|
||||||
#define OPTIMAL 1
|
#define OPTIMAL 1
|
||||||
#define INFEASIBLE 2
|
#define INFEASIBLE 2
|
||||||
#define INF_OR_UNBD 3
|
#define INF_OR_UNBD 3
|
||||||
#define UNBOUNDED 4
|
#define UNBOUNDED 4
|
||||||
#define CUTOFF 5
|
#define CUTOFF 5
|
||||||
#define ITERATION_LIMIT 6
|
#define ITERATION_LIMIT 6
|
||||||
#define NODE_LIMIT 7
|
#define NODE_LIMIT 7
|
||||||
#define TIME_LIMIT 8
|
#define TIME_LIMIT 8
|
||||||
#define SOLUTION_LIMIT 9
|
#define SOLUTION_LIMIT 9
|
||||||
#define INTERRUPTED 10
|
#define INTERRUPTED 10
|
||||||
#define NUMERIC 11
|
#define NUMERIC 11
|
||||||
#define SUBOPTIMAL 12
|
#define SUBOPTIMAL 12
|
||||||
#define INPROGRESS 13
|
#define INPROGRESS 13
|
||||||
#define USER_OBJ_LIMIT 14
|
#define USER_OBJ_LIMIT 14
|
||||||
#define WORK_LIMIT 15
|
#define WORK_LIMIT 15
|
||||||
#define MEM_LIMIT 16
|
#define MEM_LIMIT 16
|
||||||
#define PIVOT 17
|
#define PIVOT 17
|
||||||
|
|
||||||
namespace sv {
|
namespace sv {
|
||||||
using matrix = std::vector<std::vector<double>>;
|
using matrix = std::vector<std::vector<double>>;
|
||||||
using rtn = int;
|
using rtn = int;
|
||||||
class Expr;
|
class Expr;
|
||||||
class Var;
|
class Var;
|
||||||
|
|
||||||
enum class IntAttr {
|
enum class IntAttr {
|
||||||
NumConstrs,
|
NumConstrs,
|
||||||
NumVars,
|
NumVars,
|
||||||
NumIntVars,
|
NumIntVars,
|
||||||
NumBinVars,
|
NumBinVars,
|
||||||
ModelSense,
|
ModelSense,
|
||||||
IsMIP,
|
IsMIP,
|
||||||
IsMultiObj,
|
IsMultiObj,
|
||||||
Status,
|
Status,
|
||||||
SolCount,
|
SolCount,
|
||||||
Lazy,
|
Lazy,
|
||||||
NumObj,
|
NumObj,
|
||||||
NumCol
|
NumCol
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DoubleAttr {
|
enum class DoubleAttr {
|
||||||
Runtime,
|
Runtime,
|
||||||
Work,
|
Work,
|
||||||
ObjCon,
|
ObjCon,
|
||||||
LB,
|
LB,
|
||||||
UB,
|
UB,
|
||||||
Obj,
|
Obj,
|
||||||
Start,
|
Start,
|
||||||
RHS,
|
RHS,
|
||||||
Coeff,
|
Coeff,
|
||||||
MaxCoeff,
|
MaxCoeff,
|
||||||
MinCoeff,
|
MinCoeff,
|
||||||
MaxBound,
|
MaxBound,
|
||||||
MinBound,
|
MinBound,
|
||||||
ObjVal,
|
ObjVal,
|
||||||
MIPGap,
|
MIPGap,
|
||||||
IterCount,
|
IterCount,
|
||||||
NodeCount,
|
NodeCount,
|
||||||
X,
|
X,
|
||||||
Slack,
|
Slack,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StringAttr {
|
enum class StringAttr {
|
||||||
ModelName,
|
ModelName,
|
||||||
VarName,
|
VarName,
|
||||||
ConstrName,
|
ConstrName,
|
||||||
QCName,
|
QCName,
|
||||||
GenConstrName,
|
GenConstrName,
|
||||||
ObjNName,
|
ObjNName,
|
||||||
ScenNName,
|
ScenNName,
|
||||||
BatchID,
|
BatchID,
|
||||||
VTag,
|
VTag,
|
||||||
CTag,
|
CTag,
|
||||||
QCTag,
|
QCTag,
|
||||||
BatchErrorMessage
|
BatchErrorMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ConstrOper {
|
enum class ConstrOper { LESS_EQUAL, GREATER_EQUAL, EQUAL };
|
||||||
LESS_EQUAL,
|
|
||||||
GREATER_EQUAL,
|
|
||||||
EQUAL
|
|
||||||
};
|
|
||||||
|
|
||||||
|
enum class VarType {
|
||||||
|
CONTINUOUS,
|
||||||
|
BINARY,
|
||||||
|
INTEGER,
|
||||||
|
};
|
||||||
|
|
||||||
enum class VarType {
|
class Var {
|
||||||
CONTINUOUS,
|
public:
|
||||||
BINARY,
|
friend class Model;
|
||||||
INTEGER,
|
friend class LinSolver;
|
||||||
};
|
friend class Expr;
|
||||||
|
|
||||||
class Var {
|
Var(double coef = 1, VarType type_ = VarType::CONTINUOUS);
|
||||||
public:
|
double get(DoubleAttr attr);
|
||||||
friend class Model;
|
int get(IntAttr attr);
|
||||||
friend class LinSolver;
|
|
||||||
friend class Expr;
|
|
||||||
|
|
||||||
Var(double coef = 1, VarType type_ = VarType::CONTINUOUS);
|
private:
|
||||||
double get(DoubleAttr attr);
|
double coeffs;
|
||||||
int get(IntAttr attr);
|
double val;
|
||||||
|
int col;
|
||||||
|
VarType type;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
Expr operator+(const Expr &x, const Expr &y);
|
||||||
double coeffs;
|
Expr operator-(const Expr &x, const Expr &y);
|
||||||
double val;
|
Expr operator+(const Expr &x);
|
||||||
int col;
|
Expr operator+(Var x, Var y);
|
||||||
VarType type;
|
Expr operator+(Var x, double a);
|
||||||
};
|
Expr operator+(double a, Var x);
|
||||||
|
Expr operator-(const Expr &x);
|
||||||
|
Expr operator-(Var x);
|
||||||
|
Expr operator-(Var x, Var y);
|
||||||
|
Expr operator-(Var x, double a);
|
||||||
|
Expr operator-(double a, Var x);
|
||||||
|
Expr operator*(double a, Var x);
|
||||||
|
Expr operator*(Var x, double a);
|
||||||
|
Expr operator*(const Expr &x, double a);
|
||||||
|
Expr operator*(double a, const Expr &x);
|
||||||
|
Expr operator/(Var x, double a);
|
||||||
|
Expr operator/(const Expr &x, double a);
|
||||||
|
|
||||||
Expr operator+(const Expr& x, const Expr& y);
|
class Expr {
|
||||||
Expr operator-(const Expr& x, const Expr& y);
|
private:
|
||||||
Expr operator+(const Expr& x);
|
double constant;
|
||||||
Expr operator+(Var x, Var y);
|
std::vector<double> coeffs;
|
||||||
Expr operator+(Var x, double a);
|
std::vector<Var> vars;
|
||||||
Expr operator+(double a, Var x);
|
|
||||||
Expr operator-(const Expr& x);
|
|
||||||
Expr operator-(Var x);
|
|
||||||
Expr operator-(Var x, Var y);
|
|
||||||
Expr operator-(Var x, double a);
|
|
||||||
Expr operator-(double a, Var x);
|
|
||||||
Expr operator*(double a, Var x);
|
|
||||||
Expr operator*(Var x, double a);
|
|
||||||
Expr operator*(const Expr& x, double a);
|
|
||||||
Expr operator*(double a, const Expr& x);
|
|
||||||
Expr operator/(Var x, double a);
|
|
||||||
Expr operator/(const Expr& x, double a);
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
Expr(const Expr &expr) = default;
|
||||||
|
Expr(double constant = 0.0);
|
||||||
|
Expr(Var var, double coeff = 1.0);
|
||||||
|
|
||||||
class Expr
|
friend class LinSolver;
|
||||||
{
|
|
||||||
private:
|
|
||||||
double constant;
|
|
||||||
std::vector<double> coeffs;
|
|
||||||
std::vector<Var> vars;
|
|
||||||
|
|
||||||
public:
|
friend Expr operator+(const Expr &x, const Expr &y);
|
||||||
Expr(const Expr& expr) = default;
|
friend Expr operator+(const Expr &x);
|
||||||
Expr(double constant = 0.0);
|
friend Expr operator+(Var x, Var y);
|
||||||
Expr(Var var, double coeff = 1.0);
|
friend Expr operator+(Var x, double a);
|
||||||
|
friend Expr operator+(double a, Var x);
|
||||||
|
friend Expr operator-(const Expr &x, const Expr &y);
|
||||||
|
friend Expr operator-(const Expr &x);
|
||||||
|
friend Expr operator-(Var x);
|
||||||
|
friend Expr operator-(Var x, Var y);
|
||||||
|
friend Expr operator-(Var x, double a);
|
||||||
|
friend Expr operator-(double a, Var x);
|
||||||
|
friend Expr operator*(double a, Var x);
|
||||||
|
friend Expr operator*(Var x, double a);
|
||||||
|
friend Expr operator*(const Expr &x, double a);
|
||||||
|
friend Expr operator*(double a, const Expr &x);
|
||||||
|
friend Expr operator/(Var x, double a);
|
||||||
|
friend Expr operator/(const Expr &x, double a);
|
||||||
|
|
||||||
friend class LinSolver;
|
Expr &operator=(const Expr &rhs);
|
||||||
|
void operator+=(const Expr &expr);
|
||||||
friend Expr operator+(const Expr& x, const Expr& y);
|
void operator-=(const Expr &expr);
|
||||||
friend Expr operator+(const Expr& x);
|
void operator*=(double mult);
|
||||||
friend Expr operator+(Var x, Var y);
|
void operator/=(double a);
|
||||||
friend Expr operator+(Var x, double a);
|
Expr operator+(const Expr &rhs);
|
||||||
friend Expr operator+(double a, Var x);
|
Expr operator-(const Expr &rhs);
|
||||||
friend Expr operator-(const Expr& x, const Expr& y);
|
};
|
||||||
friend Expr operator-(const Expr& x);
|
} // namespace sv
|
||||||
friend Expr operator-(Var x);
|
|
||||||
friend Expr operator-(Var x, Var y);
|
|
||||||
friend Expr operator-(Var x, double a);
|
|
||||||
friend Expr operator-(double a, Var x);
|
|
||||||
friend Expr operator*(double a, Var x);
|
|
||||||
friend Expr operator*(Var x, double a);
|
|
||||||
friend Expr operator*(const Expr& x, double a);
|
|
||||||
friend Expr operator*(double a, const Expr& x);
|
|
||||||
friend Expr operator/(Var x, double a);
|
|
||||||
friend Expr operator/(const Expr& x, double a);
|
|
||||||
|
|
||||||
|
|
||||||
Expr operator=(const Expr& rhs);
|
|
||||||
void operator+=(const Expr& expr);
|
|
||||||
void operator-=(const Expr& expr);
|
|
||||||
void operator*=(double mult);
|
|
||||||
void operator/=(double a);
|
|
||||||
Expr operator+(const Expr& rhs);
|
|
||||||
Expr operator-(const Expr& rhs);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
+42
-46
@@ -3,60 +3,56 @@
|
|||||||
|
|
||||||
namespace sv {
|
namespace sv {
|
||||||
|
|
||||||
class LinSolver {
|
class LinSolver {
|
||||||
public:
|
public:
|
||||||
friend class Model;
|
friend class Model;
|
||||||
LinSolver();
|
LinSolver();
|
||||||
~LinSolver();
|
~LinSolver();
|
||||||
|
|
||||||
LinSolver(const LinSolver& solver);
|
LinSolver(const LinSolver &solver);
|
||||||
LinSolver& operator=(const LinSolver& solver);
|
LinSolver &operator=(const LinSolver &solver);
|
||||||
|
|
||||||
Var* addVars(int col, VarType type);
|
Var *addVars(int col, VarType type);
|
||||||
Var& getVar(int idx);
|
Var &getVar(int idx);
|
||||||
void addConstr(const Expr& expr, ConstrOper sense, double rhs);
|
void addConstr(const Expr &expr, ConstrOper sense, double rhs);
|
||||||
void setObjective(Expr obje, int sense = MDL_MAXIMIZE);
|
void setObjective(Expr obje, int sense = MDL_MAXIMIZE);
|
||||||
void print();
|
void print();
|
||||||
|
|
||||||
double get(DoubleAttr attr);
|
double get(DoubleAttr attr);
|
||||||
int get(IntAttr attr);
|
int get(IntAttr attr);
|
||||||
|
|
||||||
rtn optimize();
|
rtn optimize();
|
||||||
protected:
|
|
||||||
|
|
||||||
double _simplex();
|
protected:
|
||||||
rtn _pivot(std::pair<size_t, size_t>& p);
|
double _simplex();
|
||||||
rtn feasible_solution();
|
rtn _pivot(std::pair<size_t, size_t> &p);
|
||||||
void _gaussian(std::pair<size_t, size_t> p);
|
rtn feasible_solution();
|
||||||
|
void _gaussian(std::pair<size_t, size_t> p);
|
||||||
|
|
||||||
std::vector<std::pair<int, Var*>> vars;
|
std::vector<std::pair<int, Var *>> vars;
|
||||||
|
|
||||||
matrix table;
|
matrix table;
|
||||||
matrix ope_table;
|
matrix ope_table;
|
||||||
size_t cn, bn;
|
size_t cn, bn;
|
||||||
std::vector<int> basic;
|
std::vector<int> basic;
|
||||||
rtn rtn_;
|
rtn rtn_;
|
||||||
double obj_;
|
double obj_;
|
||||||
int sense;
|
int sense;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Model
|
class Model {
|
||||||
{
|
public:
|
||||||
public:
|
Model();
|
||||||
Model();
|
rtn optimize();
|
||||||
rtn optimize();
|
|
||||||
|
|
||||||
Var* addVars(int col, VarType type);
|
|
||||||
void addConstr(const Expr& expr, ConstrOper sense, double rhs);
|
|
||||||
void setObjective(Expr obje, int sense = MDL_MAXIMIZE);
|
|
||||||
|
|
||||||
double get(DoubleAttr attr);
|
|
||||||
int get(IntAttr attr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
LinSolver solver;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Var *addVars(int col, VarType type);
|
||||||
|
void addConstr(const Expr &expr, ConstrOper sense, double rhs);
|
||||||
|
void setObjective(Expr obje, int sense = MDL_MAXIMIZE);
|
||||||
|
|
||||||
|
double get(DoubleAttr attr);
|
||||||
|
int get(IntAttr attr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LinSolver solver;
|
||||||
|
};
|
||||||
|
} // namespace sv
|
||||||
|
|||||||
+44
-71
@@ -2,17 +2,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
using namespace sv;
|
using namespace sv;
|
||||||
|
|
||||||
|
Var::Var(double coef, VarType type_) : col(0), val(0), coeffs(coef), type(type_){};
|
||||||
|
|
||||||
Var::Var(double coef, VarType type_) :
|
double Var::get(DoubleAttr attr) {
|
||||||
col(0),
|
|
||||||
val(0),
|
|
||||||
coeffs(coef),
|
|
||||||
type(type_)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
double Var::get(DoubleAttr attr)
|
|
||||||
{
|
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case DoubleAttr::Coeff:
|
case DoubleAttr::Coeff:
|
||||||
return coeffs;
|
return coeffs;
|
||||||
@@ -22,13 +14,11 @@ double Var::get(DoubleAttr attr)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Var::get(IntAttr attr)
|
int Var::get(IntAttr attr) {
|
||||||
{
|
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator+(const Expr& x, const Expr& y)
|
Expr sv::operator+(const Expr &x, const Expr &y) {
|
||||||
{
|
|
||||||
Expr exp;
|
Expr exp;
|
||||||
exp.coeffs.resize(std::max(x.coeffs.size(), y.coeffs.size()), 0);
|
exp.coeffs.resize(std::max(x.coeffs.size(), y.coeffs.size()), 0);
|
||||||
for (int c = 0; c < exp.coeffs.size(); c++) {
|
for (int c = 0; c < exp.coeffs.size(); c++) {
|
||||||
@@ -43,13 +33,11 @@ Expr sv::operator+(const Expr& x, const Expr& y)
|
|||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator+(const Expr& x)
|
Expr sv::operator+(const Expr &x) {
|
||||||
{
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator+(Var x, Var y)
|
Expr sv::operator+(Var x, Var y) {
|
||||||
{
|
|
||||||
Expr exp;
|
Expr exp;
|
||||||
exp.coeffs.resize(std::max(x.get(IntAttr::NumCol) + 1, y.get(IntAttr::NumCol) + 1), 0);
|
exp.coeffs.resize(std::max(x.get(IntAttr::NumCol) + 1, y.get(IntAttr::NumCol) + 1), 0);
|
||||||
exp.coeffs.at(x.get(IntAttr::NumCol)) = x.get(DoubleAttr::Coeff);
|
exp.coeffs.at(x.get(IntAttr::NumCol)) = x.get(DoubleAttr::Coeff);
|
||||||
@@ -57,21 +45,19 @@ Expr sv::operator+(Var x, Var y)
|
|||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator+(Var x, double a)
|
Expr sv::operator+(Var x, double a) {
|
||||||
{
|
|
||||||
Expr exp;
|
Expr exp;
|
||||||
exp.coeffs.resize(x.get(IntAttr::NumCol) + 1);
|
exp.coeffs.resize(x.get(IntAttr::NumCol) + 1, 0);
|
||||||
|
exp.coeffs.at(x.get(IntAttr::NumCol)) = x.get(DoubleAttr::Coeff);
|
||||||
exp.constant = a;
|
exp.constant = a;
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator+(double a, Var x)
|
Expr sv::operator+(double a, Var x) {
|
||||||
{
|
|
||||||
return x + a;
|
return x + a;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator-(const Expr& x, const Expr& y)
|
Expr sv::operator-(const Expr &x, const Expr &y) {
|
||||||
{
|
|
||||||
Expr exp;
|
Expr exp;
|
||||||
exp.coeffs.resize(std::max(x.coeffs.size(), y.coeffs.size()), 0);
|
exp.coeffs.resize(std::max(x.coeffs.size(), y.coeffs.size()), 0);
|
||||||
for (int c = 0; c < exp.coeffs.size(); c++) {
|
for (int c = 0; c < exp.coeffs.size(); c++) {
|
||||||
@@ -79,15 +65,14 @@ Expr sv::operator-(const Expr& x, const Expr& y)
|
|||||||
exp.coeffs.at(c) = x.coeffs.at(c) - y.coeffs.at(c);
|
exp.coeffs.at(c) = x.coeffs.at(c) - y.coeffs.at(c);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
exp.coeffs.at(c) = c < x.coeffs.size() ? x.coeffs.at(c) : y.coeffs.at(c);
|
exp.coeffs.at(c) = c < x.coeffs.size() ? x.coeffs.at(c) : -y.coeffs.at(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exp.constant = x.constant + y.constant;
|
exp.constant = x.constant - y.constant;
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator-(const Expr& x)
|
Expr sv::operator-(const Expr &x) {
|
||||||
{
|
|
||||||
Expr expr(x);
|
Expr expr(x);
|
||||||
for (int c = 0; c < expr.coeffs.size(); c++) {
|
for (int c = 0; c < expr.coeffs.size(); c++) {
|
||||||
expr.coeffs.at(c) = -expr.coeffs.at(c);
|
expr.coeffs.at(c) = -expr.coeffs.at(c);
|
||||||
@@ -96,13 +81,11 @@ Expr sv::operator-(const Expr& x)
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator-(Var x)
|
Expr sv::operator-(Var x) {
|
||||||
{
|
|
||||||
return -Expr(x);
|
return -Expr(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator-(Var x, Var y)
|
Expr sv::operator-(Var x, Var y) {
|
||||||
{
|
|
||||||
Expr exp;
|
Expr exp;
|
||||||
exp.coeffs.resize(std::max(x.get(IntAttr::NumCol) + 1, y.get(IntAttr::NumCol) + 1), 0);
|
exp.coeffs.resize(std::max(x.get(IntAttr::NumCol) + 1, y.get(IntAttr::NumCol) + 1), 0);
|
||||||
exp.coeffs.at(x.get(IntAttr::NumCol)) = x.get(DoubleAttr::Coeff);
|
exp.coeffs.at(x.get(IntAttr::NumCol)) = x.get(DoubleAttr::Coeff);
|
||||||
@@ -110,31 +93,30 @@ Expr sv::operator-(Var x, Var y)
|
|||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator-(Var x, double a)
|
Expr sv::operator-(Var x, double a) {
|
||||||
{
|
Expr exp;
|
||||||
return x - Var(a);
|
exp.coeffs.resize(x.get(IntAttr::NumCol) + 1, 0);
|
||||||
|
exp.coeffs.at(x.get(IntAttr::NumCol)) = x.get(DoubleAttr::Coeff);
|
||||||
|
exp.constant = -a;
|
||||||
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator-(double a, Var x)
|
Expr sv::operator-(double a, Var x) {
|
||||||
{
|
return a + (-x);
|
||||||
return x - a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator*(double a, Var x)
|
Expr sv::operator*(double a, Var x) {
|
||||||
{
|
|
||||||
Expr exp;
|
Expr exp;
|
||||||
exp.coeffs.resize(x.get(IntAttr::NumCol) + 1, 0);
|
exp.coeffs.resize(x.get(IntAttr::NumCol) + 1, 0);
|
||||||
exp.coeffs.at(x.get(IntAttr::NumCol)) = a * x.get(DoubleAttr::Coeff);
|
exp.coeffs.at(x.get(IntAttr::NumCol)) = a * x.get(DoubleAttr::Coeff);
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator*(Var x, double a)
|
Expr sv::operator*(Var x, double a) {
|
||||||
{
|
|
||||||
return a * x;
|
return a * x;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator*(const Expr& x, double a)
|
Expr sv::operator*(const Expr &x, double a) {
|
||||||
{
|
|
||||||
Expr exp = x;
|
Expr exp = x;
|
||||||
for (int c = 0; c < exp.coeffs.size(); c++) {
|
for (int c = 0; c < exp.coeffs.size(); c++) {
|
||||||
exp.coeffs.at(c) *= a;
|
exp.coeffs.at(c) *= a;
|
||||||
@@ -143,18 +125,15 @@ Expr sv::operator*(const Expr& x, double a)
|
|||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator*(double a, const Expr& x)
|
Expr sv::operator*(double a, const Expr &x) {
|
||||||
{
|
|
||||||
return x * a;
|
return x * a;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator/(Var x, double a)
|
Expr sv::operator/(Var x, double a) {
|
||||||
{
|
|
||||||
return Expr(x) / a;
|
return Expr(x) / a;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr sv::operator/(const Expr& x, double a)
|
Expr sv::operator/(const Expr &x, double a) {
|
||||||
{
|
|
||||||
Expr exp = x;
|
Expr exp = x;
|
||||||
for (int c = 0; c < exp.coeffs.size(); c++) {
|
for (int c = 0; c < exp.coeffs.size(); c++) {
|
||||||
exp.coeffs.at(c) /= a;
|
exp.coeffs.at(c) /= a;
|
||||||
@@ -163,25 +142,24 @@ Expr sv::operator/(const Expr& x, double a)
|
|||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Expr(double constant)
|
Expr::Expr(double constant) : constant(constant) {}
|
||||||
:constant(constant)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr::Expr(Var var, double coeff)
|
Expr::Expr(Var var, double coeff) {
|
||||||
{
|
|
||||||
this->coeffs.resize(var.col + 1);
|
this->coeffs.resize(var.col + 1);
|
||||||
this->coeffs.at(var.col) = coeff;
|
this->coeffs.at(var.col) = coeff;
|
||||||
this->constant = 0;
|
this->constant = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr Expr::operator=(const Expr& rhs)
|
Expr &Expr::operator=(const Expr &rhs) {
|
||||||
{
|
if (this != &rhs) {
|
||||||
|
constant = rhs.constant;
|
||||||
|
coeffs = rhs.coeffs;
|
||||||
|
vars = rhs.vars;
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expr::operator+=(const Expr& expr)
|
void Expr::operator+=(const Expr &expr) {
|
||||||
{
|
|
||||||
coeffs.resize(std::max(coeffs.size(), expr.coeffs.size()));
|
coeffs.resize(std::max(coeffs.size(), expr.coeffs.size()));
|
||||||
for (int c = 0; c < expr.coeffs.size(); c++) {
|
for (int c = 0; c < expr.coeffs.size(); c++) {
|
||||||
coeffs.at(c) += expr.coeffs.at(c);
|
coeffs.at(c) += expr.coeffs.at(c);
|
||||||
@@ -189,8 +167,7 @@ void Expr::operator+=(const Expr& expr)
|
|||||||
constant += expr.constant;
|
constant += expr.constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expr::operator-=(const Expr& expr)
|
void Expr::operator-=(const Expr &expr) {
|
||||||
{
|
|
||||||
coeffs.resize(std::max(coeffs.size(), expr.coeffs.size()));
|
coeffs.resize(std::max(coeffs.size(), expr.coeffs.size()));
|
||||||
for (int c = 0; c < expr.coeffs.size(); c++) {
|
for (int c = 0; c < expr.coeffs.size(); c++) {
|
||||||
coeffs.at(c) -= expr.coeffs.at(c);
|
coeffs.at(c) -= expr.coeffs.at(c);
|
||||||
@@ -198,24 +175,21 @@ void Expr::operator-=(const Expr& expr)
|
|||||||
constant -= expr.constant;
|
constant -= expr.constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expr::operator*=(double mult)
|
void Expr::operator*=(double mult) {
|
||||||
{
|
|
||||||
for (int c = 0; c < coeffs.size(); c++) {
|
for (int c = 0; c < coeffs.size(); c++) {
|
||||||
coeffs.at(c) *= mult;
|
coeffs.at(c) *= mult;
|
||||||
}
|
}
|
||||||
constant *= mult;
|
constant *= mult;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expr::operator/=(double a)
|
void Expr::operator/=(double a) {
|
||||||
{
|
|
||||||
for (int c = 0; c < coeffs.size(); c++) {
|
for (int c = 0; c < coeffs.size(); c++) {
|
||||||
coeffs.at(c) /= a;
|
coeffs.at(c) /= a;
|
||||||
}
|
}
|
||||||
constant /= a;
|
constant /= a;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr Expr::operator+(const Expr& rhs)
|
Expr Expr::operator+(const Expr &rhs) {
|
||||||
{
|
|
||||||
coeffs.resize(std::max(coeffs.size(), rhs.coeffs.size()));
|
coeffs.resize(std::max(coeffs.size(), rhs.coeffs.size()));
|
||||||
for (int c = 0; c < rhs.coeffs.size(); c++) {
|
for (int c = 0; c < rhs.coeffs.size(); c++) {
|
||||||
coeffs.at(c) += rhs.coeffs.at(c);
|
coeffs.at(c) += rhs.coeffs.at(c);
|
||||||
@@ -224,8 +198,7 @@ Expr Expr::operator+(const Expr& rhs)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr Expr::operator-(const Expr& rhs)
|
Expr Expr::operator-(const Expr &rhs) {
|
||||||
{
|
|
||||||
coeffs.resize(std::max(coeffs.size(), rhs.coeffs.size()));
|
coeffs.resize(std::max(coeffs.size(), rhs.coeffs.size()));
|
||||||
for (int c = 0; c < rhs.coeffs.size(); c++) {
|
for (int c = 0; c < rhs.coeffs.size(); c++) {
|
||||||
coeffs.at(c) -= rhs.coeffs.at(c);
|
coeffs.at(c) -= rhs.coeffs.at(c);
|
||||||
|
|||||||
+20
-21
@@ -6,36 +6,35 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace sv;
|
using namespace sv;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
Model mdl;
|
Model mdl;
|
||||||
|
|
||||||
Var* int_var = mdl.addVars(3, VarType::INTEGER);
|
|
||||||
Var* con_var = mdl.addVars(2, VarType::CONTINUOUS);
|
|
||||||
|
|
||||||
mdl.addConstr(2 * int_var[0] + int_var[1], ConstrOper::LESS_EQUAL, 10);
|
Var *x = mdl.addVars(3, VarType::INTEGER);
|
||||||
mdl.addConstr(3 * int_var[0] + 6 * int_var[1], ConstrOper::LESS_EQUAL, 40);
|
Var *y = mdl.addVars(2, VarType::CONTINUOUS);
|
||||||
mdl.addConstr(3 * int_var[0] + 6 * int_var[1] + 4 * int_var[2], ConstrOper::LESS_EQUAL, 50);
|
|
||||||
mdl.addConstr(2.3 * con_var[0] + 2.6 * con_var[1], ConstrOper::LESS_EQUAL, 80);
|
|
||||||
mdl.addConstr(con_var[0] + 2 * con_var[1], ConstrOper::LESS_EQUAL, 70);
|
|
||||||
mdl.setObjective(100 * int_var[0] + 150 * int_var[1] + 120 * int_var[2] + 82.6 * con_var[0] + 90.4 * con_var[1], MDL_MAXIMIZE);
|
|
||||||
|
|
||||||
switch(mdl.optimize()) {
|
mdl.addConstr(3 * x[0] + 6 * x[1], ConstrOper::LESS_EQUAL, 28);
|
||||||
case OPTIMAL:
|
mdl.addConstr(3 * x[0] + 6 * x[1] + 4 * x[2], ConstrOper::LESS_EQUAL, 30);
|
||||||
cout << "OPTIMAL SOLUTION: " << mdl.get(DoubleAttr::Obj) << endl;
|
mdl.addConstr(3 * y[0] + 2 * y[1], ConstrOper::LESS_EQUAL, 80);
|
||||||
|
mdl.addConstr(y[0] + 2 * y[1], ConstrOper::LESS_EQUAL, 70);
|
||||||
|
mdl.addConstr(2 * x[1] + x[2], ConstrOper::EQUAL, 7);
|
||||||
|
mdl.setObjective(100 * x[0] + 150 * x[1] + 120 * x[2] + 80 * y[0] + 90 * y[1] + 15,
|
||||||
|
MDL_MAXIMIZE);
|
||||||
|
|
||||||
|
switch (mdl.optimize()) {
|
||||||
|
case OPTIMAL:
|
||||||
|
cout << "OPTIMAL SOLUTION: " << mdl.get(DoubleAttr::Obj) << endl;
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
cout << "integer var [" << i << "] : " << int_var[i].get(DoubleAttr::X) << endl;
|
cout << "integer var [" << i << "] : " << x[i].get(DoubleAttr::X) << endl;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
cout << "continuous var [" << i << "] : " << con_var[i].get(DoubleAttr::X) << endl;
|
cout << "continuous var [" << i << "] : " << y[i].get(DoubleAttr::X) << endl;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case INFEASIBLE:
|
case INFEASIBLE:
|
||||||
cout << "INFEASIBLE MODEL" << endl;
|
cout << "INFEASIBLE MODEL" << endl;
|
||||||
break;
|
break;
|
||||||
case UNBOUNDED:
|
case UNBOUNDED:
|
||||||
cout << "UNBOUNDED SOLUTION" << endl;
|
cout << "UNBOUNDED SOLUTION" << endl;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|||||||
+212
-195
@@ -5,68 +5,53 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <cassert>
|
#include <cmath>
|
||||||
#include <cstring>
|
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <math.h>
|
#include <limits>
|
||||||
|
|
||||||
using namespace sv;
|
using namespace sv;
|
||||||
|
|
||||||
using std::make_pair;
|
|
||||||
using std::pair;
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
using std::make_pair;
|
||||||
|
using std::pair;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
|
struct Node {
|
||||||
struct Node
|
|
||||||
{
|
|
||||||
LinSolver solver;
|
LinSolver solver;
|
||||||
double lower_bound;
|
double bound; // LP bound in true-objective space
|
||||||
double upper_bound;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LinSolver::LinSolver() :
|
LinSolver::LinSolver() : obj_(0), rtn_(LOADED), cn(0), bn(1), sense(0) {}
|
||||||
obj_(0),
|
|
||||||
rtn_(LOADED),
|
|
||||||
cn(0),
|
|
||||||
bn(1),
|
|
||||||
sense(0)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
sv::LinSolver::~LinSolver() {
|
||||||
|
for (auto &var : vars) {
|
||||||
sv::LinSolver::~LinSolver()
|
|
||||||
{
|
|
||||||
for (auto& var : vars) {
|
|
||||||
delete[] var.second;
|
delete[] var.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sv::LinSolver::LinSolver(const LinSolver& solver)
|
sv::LinSolver::LinSolver(const LinSolver &solver) {
|
||||||
{
|
|
||||||
*this = solver;
|
*this = solver;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinSolver& sv::LinSolver::operator=(const LinSolver& solver)
|
LinSolver &sv::LinSolver::operator=(const LinSolver &solver) {
|
||||||
{
|
|
||||||
if (this == &solver) {
|
if (this == &solver) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
for (auto& var : vars) {
|
for (auto &var : vars) {
|
||||||
delete[] var.second;
|
delete[] var.second;
|
||||||
}
|
}
|
||||||
vars.clear();
|
vars.clear();
|
||||||
vars.reserve(solver.vars.size());
|
vars.reserve(solver.vars.size());
|
||||||
for (auto& var : solver.vars) {
|
for (auto &var : solver.vars) {
|
||||||
vars.push_back(std::make_pair(var.first, new Var[var.first]));
|
vars.push_back(std::make_pair(var.first, new Var[var.first]));
|
||||||
for (int i = 0; i < var.first; i++) {
|
for (int i = 0; i < var.first; i++) {
|
||||||
vars.back().second[i] = var.second[i];
|
vars.back().second[i] = var.second[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cn = solver.cn;
|
cn = solver.cn;
|
||||||
|
bn = solver.bn;
|
||||||
table = solver.table;
|
table = solver.table;
|
||||||
cn = solver.cn, bn = solver.bn;
|
|
||||||
basic = solver.basic;
|
basic = solver.basic;
|
||||||
rtn_ = solver.rtn_;
|
rtn_ = solver.rtn_;
|
||||||
obj_ = solver.obj_;
|
obj_ = solver.obj_;
|
||||||
@@ -75,85 +60,73 @@ LinSolver& sv::LinSolver::operator=(const LinSolver& solver)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Var* LinSolver::addVars(int num, VarType type)
|
Var *LinSolver::addVars(int num, VarType type) {
|
||||||
{
|
Var *var = new Var[num];
|
||||||
Var* var = new Var[num];
|
|
||||||
for (int c = 0; c < num; c++) {
|
for (int c = 0; c < num; c++) {
|
||||||
var[c].col = c + cn, var[c].type = type;
|
var[c].col = c + cn;
|
||||||
|
var[c].type = type;
|
||||||
}
|
}
|
||||||
vars.push_back(std::make_pair(num, var));
|
vars.push_back(std::make_pair(num, var));
|
||||||
cn += num;
|
cn += num;
|
||||||
return vars.back().second;
|
return vars.back().second;
|
||||||
}
|
}
|
||||||
|
|
||||||
Var& sv::LinSolver::getVar(int idx)
|
Var &sv::LinSolver::getVar(int idx) {
|
||||||
{
|
assert(idx >= 0 && idx < static_cast<int>(cn));
|
||||||
assert(idx >= 0 && idx < cn);
|
|
||||||
static Var err_var;
|
static Var err_var;
|
||||||
for (auto& var : vars) {
|
int offset = 0;
|
||||||
if (var.first <= idx) {
|
for (auto &var : vars) {
|
||||||
idx -= var.first;
|
if (idx < offset + var.first) {
|
||||||
}
|
return var.second[idx - offset];
|
||||||
else {
|
|
||||||
return var.second[idx];
|
|
||||||
}
|
}
|
||||||
|
offset += var.first;
|
||||||
}
|
}
|
||||||
return err_var;
|
return err_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinSolver::addConstr(const Expr& expr, ConstrOper sense, double rhs)
|
void LinSolver::addConstr(const Expr &expr, ConstrOper sense, double rhs) {
|
||||||
{
|
if (sense == ConstrOper::EQUAL) {
|
||||||
|
addConstr(expr, ConstrOper::LESS_EQUAL, rhs);
|
||||||
|
addConstr(expr, ConstrOper::GREATER_EQUAL, rhs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bn++;
|
||||||
if (sense == ConstrOper::LESS_EQUAL) {
|
if (sense == ConstrOper::LESS_EQUAL) {
|
||||||
bn++;
|
|
||||||
table.push_back(vector<double>(1, rhs - expr.constant));
|
table.push_back(vector<double>(1, rhs - expr.constant));
|
||||||
table.back().insert(table.back().end(), expr.coeffs.begin(), expr.coeffs.end());
|
table.back().insert(table.back().end(), expr.coeffs.begin(), expr.coeffs.end());
|
||||||
}
|
}
|
||||||
else if (sense == ConstrOper::GREATER_EQUAL) {
|
else {
|
||||||
bn++;
|
|
||||||
table.push_back(vector<double>(1, expr.constant - rhs));
|
table.push_back(vector<double>(1, expr.constant - rhs));
|
||||||
for (int coeff : expr.coeffs) {
|
for (double coeff : expr.coeffs) {
|
||||||
table.back().push_back(-coeff);
|
table.back().push_back(-coeff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
addConstr(expr, ConstrOper::LESS_EQUAL, rhs);
|
for (size_t c = table.back().size(); c <= cn; c++) {
|
||||||
addConstr(expr, ConstrOper::GREATER_EQUAL, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int c = table.back().size(); c <= cn; c++) {
|
|
||||||
table.back().push_back(0);
|
table.back().push_back(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinSolver::setObjective(Expr obje, int _sense)
|
void LinSolver::setObjective(Expr obje, int _sense) {
|
||||||
{
|
|
||||||
assert(_sense == 1 || _sense == -1);
|
assert(_sense == 1 || _sense == -1);
|
||||||
if (sense == 0) {
|
if (sense == 0) {
|
||||||
table.insert(table.begin(), obje.coeffs);
|
table.insert(table.begin(), obje.coeffs);
|
||||||
table.front().insert(table.front().begin(), -obje.constant);
|
|
||||||
for (int c = obje.coeffs.size() + 1; c <= cn; c++) {
|
|
||||||
table.front().push_back(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
table.front().front() = -obje.constant;
|
table.front() = obje.coeffs;
|
||||||
for (int col = 0; col < cn; col++) {
|
|
||||||
if (col < obje.coeffs.size()) {
|
|
||||||
table.front().at(col + 1) = obje.coeffs.at(col);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
table.front().at(col) = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (int row = 0; row < table.front().size(); row++) {
|
table.front().insert(table.front().begin(), -obje.constant);
|
||||||
table.front().at(row) = _sense * table.front().at(row);
|
for (size_t c = obje.coeffs.size() + 1; c <= cn; c++) {
|
||||||
|
table.front().push_back(0);
|
||||||
|
}
|
||||||
|
for (size_t col = 0; col < table.front().size(); col++) {
|
||||||
|
table.front().at(col) = _sense * table.front().at(col);
|
||||||
}
|
}
|
||||||
sense = _sense;
|
sense = _sense;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtn LinSolver::optimize()
|
rtn LinSolver::optimize() {
|
||||||
{
|
|
||||||
assert(sense);
|
assert(sense);
|
||||||
ope_table = table;
|
ope_table = table;
|
||||||
rtn_ = LOADED;
|
rtn_ = LOADED;
|
||||||
@@ -163,18 +136,22 @@ rtn LinSolver::optimize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rtn_ == OPTIMAL) {
|
if (rtn_ == OPTIMAL) {
|
||||||
cn = ope_table.front().size() - bn;
|
const size_t num_vars = ope_table.front().size() - bn;
|
||||||
for (int row = 1; row < bn; row++) {
|
cn = num_vars;
|
||||||
if (basic.at(row - 1) - 1 < cn) {
|
for (size_t i = 0; i < num_vars; i++) {
|
||||||
getVar(basic.at(row - 1) - 1).val = ope_table.at(row).front();
|
getVar(static_cast<int>(i)).val = 0;
|
||||||
|
}
|
||||||
|
for (size_t row = 1; row < bn; row++) {
|
||||||
|
int var_idx = basic.at(row - 1) - 1;
|
||||||
|
if (var_idx >= 0 && static_cast<size_t>(var_idx) < num_vars) {
|
||||||
|
getVar(var_idx).val = ope_table.at(row).front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rtn_;
|
return rtn_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinSolver::print()
|
void LinSolver::print() {
|
||||||
{
|
|
||||||
for (size_t row = 0; row < ope_table.size(); row++) {
|
for (size_t row = 0; row < ope_table.size(); row++) {
|
||||||
for (size_t col = 0; col < ope_table.front().size(); col++) {
|
for (size_t col = 0; col < ope_table.front().size(); col++) {
|
||||||
cout << ope_table.at(row).at(col) << "\t";
|
cout << ope_table.at(row).at(col) << "\t";
|
||||||
@@ -183,163 +160,206 @@ void LinSolver::print()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model()
|
Model::Model() {}
|
||||||
{
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool is_integer_type(VarType type) {
|
||||||
|
return type == VarType::INTEGER || type == VarType::BINARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtn Model::optimize()
|
bool is_fractional(double val, double eps = 1e-6) {
|
||||||
{
|
return fabs(val - std::round(val)) > eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_better(double candidate, double incumbent, int sense, double eps = 1e-10) {
|
||||||
|
if (sense == MDL_MAXIMIZE) {
|
||||||
|
return candidate > incumbent + eps;
|
||||||
|
}
|
||||||
|
return candidate < incumbent - eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
rtn Model::optimize() {
|
||||||
solver.optimize();
|
solver.optimize();
|
||||||
if (solver.rtn_ != OPTIMAL) {
|
if (solver.rtn_ != OPTIMAL) {
|
||||||
return solver.rtn_;
|
return solver.rtn_;
|
||||||
}
|
}
|
||||||
|
|
||||||
double global_upper_bound = solver.obj_, global_lower_bound = 0;
|
const int sense = solver.sense;
|
||||||
|
const int num_vars = solver.get(IntAttr::NumVars);
|
||||||
|
|
||||||
std::stack<Node> list_;
|
bool has_integer = false;
|
||||||
|
for (int i = 0; i < num_vars; i++) {
|
||||||
Node root_node = { solver, 0, solver.obj_ };
|
if (is_integer_type(solver.getVar(i).type)) {
|
||||||
Node incumbent_node = root_node;
|
has_integer = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!has_integer) {
|
||||||
|
return solver.rtn_;
|
||||||
|
}
|
||||||
|
|
||||||
|
double best_obj = (sense == MDL_MAXIMIZE) ? -std::numeric_limits<double>::infinity()
|
||||||
|
: std::numeric_limits<double>::infinity();
|
||||||
|
bool found_integer = false;
|
||||||
|
Node incumbent_node{solver, solver.get(DoubleAttr::Obj)};
|
||||||
|
|
||||||
|
std::stack<Node> open_nodes;
|
||||||
|
open_nodes.push(Node{solver, solver.get(DoubleAttr::Obj)});
|
||||||
|
while (!open_nodes.empty()) {
|
||||||
|
Node current_node = std::move(open_nodes.top());
|
||||||
|
open_nodes.pop();
|
||||||
|
|
||||||
|
if (found_integer && !is_better(current_node.bound, best_obj, sense)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
list_.push(root_node);
|
|
||||||
while (list_.size() && global_upper_bound - global_lower_bound > 1e-10) {
|
|
||||||
Node current_node = list_.top();
|
|
||||||
list_.pop();
|
|
||||||
current_node.solver.optimize();
|
current_node.solver.optimize();
|
||||||
|
if (current_node.solver.get(IntAttr::Status) != OPTIMAL) {
|
||||||
if (current_node.solver.get(IntAttr::Status) == OPTIMAL) {
|
continue;
|
||||||
int branch_var_index = -1;
|
}
|
||||||
|
|
||||||
for (int i = 0; i < current_node.solver.get(IntAttr::NumVars); i++) {
|
const double lp_obj = current_node.solver.get(DoubleAttr::Obj);
|
||||||
if (current_node.solver.getVar(i).type == VarType::INTEGER) {
|
current_node.bound = lp_obj;
|
||||||
if (fabs(int(current_node.solver.getVar(i).val) - current_node.solver.getVar(i).val) > 1e-10) {
|
|
||||||
branch_var_index = i;
|
if (found_integer && !is_better(lp_obj, best_obj, sense)) {
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
int branch_var_index = -1;
|
||||||
|
for (int i = 0; i < current_node.solver.get(IntAttr::NumVars); i++) {
|
||||||
|
Var &var = current_node.solver.getVar(i);
|
||||||
|
if (!is_integer_type(var.type)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
if (is_fractional(var.val)) {
|
||||||
if (branch_var_index == -1) {
|
if (branch_var_index < 0) {
|
||||||
current_node.lower_bound = current_node.solver.obj_;
|
branch_var_index = i;
|
||||||
current_node.upper_bound = current_node.solver.obj_;
|
|
||||||
if (current_node.lower_bound > global_lower_bound) {
|
|
||||||
global_lower_bound = current_node.lower_bound;
|
|
||||||
incumbent_node = current_node;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (current_node.upper_bound >= global_lower_bound) {
|
// Snap near-integer values so later checks / output stay clean
|
||||||
const Var& branch_var = current_node.solver.getVar(branch_var_index);
|
var.val = std::round(var.val);
|
||||||
int left_var_bound = branch_var.val;
|
|
||||||
int right_var_bound = branch_var.val + 1;
|
|
||||||
|
|
||||||
Node left_node = current_node;
|
|
||||||
left_node.solver.addConstr(branch_var, ConstrOper::LESS_EQUAL, left_var_bound);
|
|
||||||
list_.push(left_node);
|
|
||||||
|
|
||||||
Node right_node = current_node;
|
|
||||||
right_node.solver.addConstr(branch_var, ConstrOper::GREATER_EQUAL, right_var_bound);
|
|
||||||
list_.push(right_node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (branch_var_index == -1) {
|
||||||
|
if (!found_integer || is_better(lp_obj, best_obj, sense)) {
|
||||||
|
best_obj = lp_obj;
|
||||||
|
found_integer = true;
|
||||||
|
incumbent_node = current_node;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Var &branch_var = current_node.solver.getVar(branch_var_index);
|
||||||
|
const int left_bound = static_cast<int>(std::floor(branch_var.val));
|
||||||
|
const int right_bound = left_bound + 1;
|
||||||
|
|
||||||
|
Node left_node = current_node;
|
||||||
|
left_node.solver.addConstr(branch_var, ConstrOper::LESS_EQUAL, left_bound);
|
||||||
|
open_nodes.push(std::move(left_node));
|
||||||
|
|
||||||
|
Node right_node = current_node;
|
||||||
|
right_node.solver.addConstr(branch_var, ConstrOper::GREATER_EQUAL, right_bound);
|
||||||
|
open_nodes.push(std::move(right_node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!found_integer) {
|
||||||
|
return solver.rtn_ = INFEASIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
solver.rtn_ = incumbent_node.solver.rtn_;
|
solver.rtn_ = incumbent_node.solver.rtn_;
|
||||||
solver.obj_ = incumbent_node.solver.obj_;
|
solver.obj_ = incumbent_node.solver.obj_;
|
||||||
for (int i = 0; i < solver.cn; i++) {
|
for (int i = 0; i < solver.get(IntAttr::NumVars); i++) {
|
||||||
solver.getVar(i).val = incumbent_node.solver.getVar(i).val;
|
solver.getVar(i).val = incumbent_node.solver.getVar(i).val;
|
||||||
}
|
}
|
||||||
return solver.rtn_;
|
return solver.rtn_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Var* sv::Model::addVars(int col, VarType type)
|
Var *sv::Model::addVars(int col, VarType type) {
|
||||||
{
|
|
||||||
return solver.addVars(col, type);
|
return solver.addVars(col, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sv::Model::addConstr(const Expr& expr, ConstrOper sense, double rhs)
|
void sv::Model::addConstr(const Expr &expr, ConstrOper sense, double rhs) {
|
||||||
{
|
solver.addConstr(expr, sense, rhs);
|
||||||
return solver.addConstr(expr, sense, rhs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sv::Model::setObjective(Expr obje, int sense)
|
void sv::Model::setObjective(Expr obje, int sense) {
|
||||||
{
|
solver.setObjective(obje, sense);
|
||||||
return solver.setObjective(obje, sense);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double sv::Model::get(DoubleAttr attr)
|
double sv::Model::get(DoubleAttr attr) {
|
||||||
{
|
|
||||||
return solver.get(attr);
|
return solver.get(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sv::Model::get(IntAttr attr)
|
int sv::Model::get(IntAttr attr) {
|
||||||
{
|
|
||||||
return solver.get(attr);
|
return solver.get(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
double LinSolver::get(DoubleAttr attr)
|
double LinSolver::get(DoubleAttr attr) {
|
||||||
{
|
|
||||||
return -sense * obj_;
|
return -sense * obj_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LinSolver::get(IntAttr attr)
|
int LinSolver::get(IntAttr attr) {
|
||||||
{
|
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case IntAttr::NumVars:
|
case IntAttr::NumVars:
|
||||||
return cn;
|
return static_cast<int>(cn);
|
||||||
case IntAttr::Status:
|
case IntAttr::Status:
|
||||||
return rtn_;
|
return rtn_;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double LinSolver::_simplex()
|
double LinSolver::_simplex() {
|
||||||
{
|
|
||||||
pair<size_t, size_t> t;
|
pair<size_t, size_t> t;
|
||||||
while (1) {
|
while (true) {
|
||||||
rtn_ = _pivot(t);
|
rtn_ = _pivot(t);
|
||||||
if (rtn_ == OPTIMAL || rtn_ == UNBOUNDED) {
|
if (rtn_ == OPTIMAL || rtn_ == UNBOUNDED) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_gaussian(t);
|
_gaussian(t);
|
||||||
}
|
}
|
||||||
return obj_ = ope_table.front().front();
|
return obj_ = ope_table.front().front();
|
||||||
}
|
}
|
||||||
|
|
||||||
rtn LinSolver::feasible_solution()
|
rtn LinSolver::feasible_solution() {
|
||||||
{
|
for (size_t row = 1; row < bn; row++) {
|
||||||
for (int row = 1; row < bn; row++) {
|
|
||||||
ope_table.front().push_back(0);
|
ope_table.front().push_back(0);
|
||||||
for (int col = 1; col < bn; col++) {
|
for (size_t col = 1; col < bn; col++) {
|
||||||
ope_table.at(row).push_back(col == row ? 1 : 0);
|
ope_table.at(row).push_back(col == row ? 1.0 : 0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cn = ope_table.front().size();
|
cn = ope_table.front().size();
|
||||||
basic.clear();
|
basic.clear();
|
||||||
|
basic.reserve(bn - 1);
|
||||||
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(static_cast<int>(cn - bn + i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 判断初始解是否为可行解 ===
|
// Check whether the initial basic solution is feasible
|
||||||
bool initial_feasible = true;
|
bool initial_feasible = true;
|
||||||
for (int row = 1; row < bn; row++) {
|
for (size_t row = 1; row < bn; row++) {
|
||||||
if (ope_table.at(row).front() < 0) {
|
if (ope_table.at(row).front() < 0) {
|
||||||
initial_feasible = false;
|
initial_feasible = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 构造初始可行解 ===
|
// Two-phase method when the initial basis is infeasible
|
||||||
if (!initial_feasible) {
|
if (!initial_feasible) {
|
||||||
vector<double> coeff = ope_table.front();
|
vector<double> coeff = ope_table.front();
|
||||||
ope_table.front() = vector<double>(cn, .0);
|
ope_table.front() = vector<double>(cn, 0.0);
|
||||||
ope_table.front().push_back(1);
|
ope_table.front().push_back(1);
|
||||||
pair<size_t, size_t> t = { -1 ,cn };
|
pair<size_t, size_t> t = {static_cast<size_t>(-1), cn};
|
||||||
|
|
||||||
for (int row = 1; row < bn; row++) {
|
for (size_t row = 1; row < bn; row++) {
|
||||||
ope_table.at(row).push_back(-1);
|
ope_table.at(row).push_back(-1);
|
||||||
if (t.first == -1 || ope_table.at(row).front() < ope_table.at(t.first).front()) {
|
if (t.first == static_cast<size_t>(-1) ||
|
||||||
|
ope_table.at(row).front() < ope_table.at(t.first).front()) {
|
||||||
t.first = row;
|
t.first = row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,29 +369,30 @@ rtn LinSolver::feasible_solution()
|
|||||||
return rtn_ = INFEASIBLE;
|
return rtn_ = INFEASIBLE;
|
||||||
}
|
}
|
||||||
rtn_ = LOADED;
|
rtn_ = LOADED;
|
||||||
// if the x0 in B, we should pivot it.
|
|
||||||
auto iter = find(basic.begin(), basic.end(), cn);
|
// If artificial variable remains basic, pivot it out
|
||||||
|
auto iter = find(basic.begin(), basic.end(), static_cast<int>(cn));
|
||||||
if (iter != basic.end()) {
|
if (iter != basic.end()) {
|
||||||
for (int col = 1; col < ope_table.front().size(); col++) {
|
for (size_t col = 1; col < ope_table.front().size(); col++) {
|
||||||
if (fabs(ope_table.front().at(col)) > 1e-10) {
|
if (fabs(ope_table.front().at(col)) > 1e-10) {
|
||||||
t = make_pair(iter - basic.begin() + 1, col);
|
t = make_pair(static_cast<size_t>(iter - basic.begin() + 1), col);
|
||||||
_gaussian(t);
|
_gaussian(t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int row = 0; row < bn; row++) {
|
for (size_t row = 0; row < bn; row++) {
|
||||||
ope_table.at(row).pop_back();
|
ope_table.at(row).pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// recover the coefficient line
|
// Restore original objective row and re-express in current basis
|
||||||
for (int col = 0; col < cn; col++) {
|
for (size_t col = 0; col < cn; col++) {
|
||||||
ope_table.front().at(col) = coeff.at(col);
|
ope_table.front().at(col) = coeff.at(col);
|
||||||
}
|
}
|
||||||
for (int row = 1; row <= basic.size(); row++) {
|
for (size_t row = 1; row <= basic.size(); row++) {
|
||||||
int norm = ope_table.front().at(basic.at(row - 1));
|
double norm = ope_table.front().at(basic.at(row - 1));
|
||||||
for (int col = 0; col < cn; col++) {
|
for (size_t col = 0; col < cn; col++) {
|
||||||
ope_table.front().at(col) -= norm * ope_table.at(row).at(col);
|
ope_table.front().at(col) -= norm * ope_table.at(row).at(col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,15 +400,15 @@ rtn LinSolver::feasible_solution()
|
|||||||
return rtn_;
|
return rtn_;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtn LinSolver::_pivot(pair<size_t, size_t>& p)
|
rtn LinSolver::_pivot(pair<size_t, size_t> &p) {
|
||||||
{
|
|
||||||
p = make_pair(0, 0);
|
p = make_pair(0, 0);
|
||||||
double cmin = DBL_MAX;
|
double cmin = DBL_MAX;
|
||||||
vector<double> coef = ope_table.front();
|
const vector<double> &coef = ope_table.front();
|
||||||
|
|
||||||
// === 非主轴元素中找最小值 ===
|
// Entering variable: most negative reduced cost
|
||||||
for (size_t col = 1; col < coef.size(); col++) {
|
for (size_t col = 1; col < coef.size(); col++) {
|
||||||
if (cmin > coef.at(col) && find(basic.begin(), basic.end(), col) == basic.end()) {
|
if (cmin > coef.at(col) &&
|
||||||
|
find(basic.begin(), basic.end(), static_cast<int>(col)) == basic.end()) {
|
||||||
cmin = coef.at(col);
|
cmin = coef.at(col);
|
||||||
p.second = col;
|
p.second = col;
|
||||||
}
|
}
|
||||||
@@ -395,51 +416,47 @@ rtn LinSolver::_pivot(pair<size_t, size_t>& p)
|
|||||||
if (cmin >= 0) {
|
if (cmin >= 0) {
|
||||||
return OPTIMAL;
|
return OPTIMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
double bmin = DBL_MAX;
|
double bmin = DBL_MAX;
|
||||||
for (size_t row = 1; row < bn; row++) {
|
for (size_t row = 1; row < bn; row++) {
|
||||||
double tmp = ope_table.at(row).front() / ope_table.at(row).at(p.second);
|
const double pivot_col = ope_table.at(row).at(p.second);
|
||||||
if (ope_table.at(row).at(p.second) > 0 && bmin > tmp) {
|
if (pivot_col > 0) {
|
||||||
bmin = tmp;
|
const double tmp = ope_table.at(row).front() / pivot_col;
|
||||||
p.first = row;
|
if (bmin > tmp) {
|
||||||
|
bmin = tmp;
|
||||||
|
p.first = row;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abs(bmin - DBL_MAX) < 1e-10) {
|
if (bmin >= DBL_MAX / 2) {
|
||||||
return UNBOUNDED;
|
return UNBOUNDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto iter = basic.begin(); iter != basic.end(); iter++) {
|
basic.at(p.first - 1) = static_cast<int>(p.second);
|
||||||
if (ope_table.at(p.first).at(*iter) != 0) {
|
|
||||||
*iter = p.second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(basic.at(p.first - 1) == p.second);
|
|
||||||
return PIVOT;
|
return PIVOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinSolver::_gaussian(pair<size_t, size_t> p)
|
void LinSolver::_gaussian(pair<size_t, size_t> p) {
|
||||||
{
|
|
||||||
size_t x = p.first, y = p.second;
|
size_t x = p.first, y = p.second;
|
||||||
|
|
||||||
// === 主行归一化 ===
|
// Normalize pivot row
|
||||||
double norm = ope_table.at(x).at(y);
|
double norm = ope_table.at(x).at(y);
|
||||||
for (size_t col = 0; col < ope_table.at(x).size(); col++) {
|
for (size_t col = 0; col < ope_table.at(x).size(); col++) {
|
||||||
ope_table.at(x).at(col) /= norm;
|
ope_table.at(x).at(col) /= norm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 其余行变换 ===
|
// Eliminate pivot column in other rows
|
||||||
for (size_t row = 0; row < bn; row++) {
|
for (size_t row = 0; row < bn; row++) {
|
||||||
if (row == x) {
|
if (row == x) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ope_table.at(row).at(y) != 0) {
|
if (ope_table.at(row).at(y) != 0) {
|
||||||
double norm = ope_table.at(row).at(y);
|
double row_norm = ope_table.at(row).at(y);
|
||||||
for (size_t col = 0; col < ope_table.at(x).size(); col++) {
|
for (size_t col = 0; col < ope_table.at(x).size(); col++) {
|
||||||
ope_table.at(row).at(col) = ope_table.at(row).at(col) - norm * ope_table.at(x).at(col);
|
ope_table.at(row).at(col) -= row_norm * ope_table.at(x).at(col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
basic.at(x - 1) = y; // 换元
|
basic.at(x - 1) = static_cast<int>(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user