This commit is contained in:
2023-07-21 23:52:15 +08:00
parent cfab5f1321
commit a192717e49
5 changed files with 121 additions and 31 deletions

27
pom.xml
View File

@@ -16,6 +16,33 @@
<properties>
<java.version>17</java.version>
</properties>
<repositories>
<repository>
<id>aliyun</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>aliyun</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -2,6 +2,7 @@ package cn.lihongjie.coal.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -11,7 +12,7 @@ public class CoalBlendResult {
private long numConflicts = 0;
private long wallTime = 0;
private long userTime = 0;
private List<CoalInfo> coals;
private List<CoalInfo> coals = new ArrayList<>();
private int totalCount;
public String tableString() {

View File

@@ -62,5 +62,12 @@ public class CoalInfo {
return String.format("%s\t%20s\t%s", name, percentString, paramString);
}
public void calPercent2() {
// percents.stream().reduce(x -> x.)
}
}

View File

@@ -1,13 +1,11 @@
package cn.lihongjie.coal.service;
import ch.qos.logback.core.BasicStatusManager;
import cn.lihongjie.coal.dto.*;
import com.google.ortools.Loader;
import com.google.ortools.sat.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.util.ArithmeticUtils;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@@ -30,34 +28,82 @@ public class CoalService {
public CoalBlendResult blend(CoalBlendRequest request) {
Loader.loadNativeLibraries();
CoalBlendResult result = new CoalBlendResult();
result.setCoals(new ArrayList<>());
CpModel model = new CpModel();
int index = 0;
List<IntVar> vars = new ArrayList<>();
for (CoalInfo coal : request.getCoals()) {
IntVar x = model.newIntVar(Math.max(coal.getMin(), 0), Math.min(coal.getMax(), 100), "x" + index++);
vars.add(x);
}
List<IntVar> vars = createPercentVars(request, model);
// 添加各种约束条件
addConstrains(request, model, vars);
// 各种煤比例之和为 100
model.addEquality(LinearExpr.sum(vars.toArray(new LinearArgument[0])), 100);
// 初始化求解器
CpSolver cpSolver = new CpSolver();
cpSolver.setLogCallback(x -> log.info(x));
SatParameters.Builder parameters = cpSolver.getParameters();
parameters.setEnumerateAllSolutions(true);
parameters.setEnumerateAllSolutions(false);
parameters.setMaxTimeInSeconds(request.getMaxTime());
parameters.setLogSearchProgress(true);
parameters.setSearchBranching(SatParameters.SearchBranching.FIXED_SEARCH);
parameters.setLogSearchProgress(false);
parameters.setFillAdditionalSolutionsInResponse(true);
// 开始求最优解
List<CoalConstraint> sorted = request.getConstraints().stream().filter(x -> x.getPriority()!=null).sorted(Comparator.comparing(CoalConstraint::getPriority)).toList();
for (CoalConstraint constraint : sorted) {
log.info("使用约束 {}", constraint);
LinearExpr weightedSum = LinearExpr.weightedSum(vars.toArray(new IntVar[0]), request.getCoals().stream().mapToLong(x -> (long) (x.getParamVal(constraint.getCode()) * 100)).toArray());
if (constraint.getOrder() == -1) {
model.maximize(weightedSum);
} else {
model.minimize(weightedSum);
}
CpSolverStatus status = cpSolver.solve(model);
if (status == CpSolverStatus.FEASIBLE || status == CpSolverStatus.OPTIMAL) {
double constrainVal = cpSolver.objectiveValue();
// model.clearHints();
//
// for (IntVar var : vars) {
// model.addHint(var, cpSolver.value(var));
//
// }
if (constraint.getOrder() == -1) {
model.addLessOrEqual(weightedSum, (long) constrainVal);
log.info("添加新的条件 sum({}) <= {}", constraint.getCode(), constrainVal);
} else {
model.addGreaterOrEqual(weightedSum, (long) constrainVal);
log.info("添加新的条件 sum({}) >= {}", constraint.getCode(), constrainVal);
}
String validate = model.validate();
log.info(validate);
} else {
log.warn("无法求解: " + status);
}
}
// 记录结果
//
cpSolver.getParameters().setEnumerateAllSolutions(true);
CpSolverStatus solverStatus = cpSolver.solve(model, new CpSolverSolutionCallback() {
@Override
public void onSolutionCallback() {
@@ -100,21 +146,28 @@ public class CoalService {
}
});
int totalCount = result.getCoals().size();
sortAndSelect(request, result);
result.setTotalCount(totalCount);
result.setNumBranches(cpSolver.numBranches());
result.setNumConflicts(cpSolver.numConflicts());
result.setUserTime((long) cpSolver.userTime());
result.setWallTime((long) cpSolver.wallTime());
return result;
}
private static List<IntVar> createPercentVars(CoalBlendRequest request, CpModel model) {
int index = 0;
List<IntVar> vars = new ArrayList<>();
for (CoalInfo coal : request.getCoals()) {
IntVar x = model.newIntVar(Math.max(coal.getMin(), 0), Math.min(coal.getMax(), 100), "x" + index++);
vars.add(x);
}
return vars;
}
private void sortAndSelect(CoalBlendRequest request, CoalBlendResult result) {
@@ -145,6 +198,7 @@ public class CoalService {
}
result.setCoals(result.getCoals().stream().sorted(c).limit(request.getCount()).collect(Collectors.toList()));
result.getCoals().forEach(x -> x.calPercent2());
}
@@ -187,11 +241,13 @@ public class CoalService {
}
private void addConstrains(CoalBlendRequest request, CpModel model, List<IntVar> vars) {
// 各种煤比例之和为 100
model.addEquality(LinearExpr.sum(vars.toArray(new LinearArgument[0])), 100);
if (request.getType() == 2) {
IntVar gcd = model.newIntVar(2, request.getPercent2Sum(), "gcd");
IntVar gcd = model.newIntVar(1, 100, "gcd");
List<IntVar> varGcdList = new ArrayList<>();
for (IntVar var : vars) {
@@ -211,8 +267,6 @@ public class CoalService {
model.addLessOrEqual(LinearExpr.sum(varGcdList.toArray(new IntVar[0])), request.getPercent2Sum());
}
for (CoalConstraint constrain : request.getConstraints()) {

View File

@@ -1,5 +1,6 @@
{
"type": 1,
"percent2Sum": 5,
"maxTime": 100,
"constraints": [
{
@@ -67,15 +68,15 @@
"parameters": [
{
"code": "param1",
"value": 2
},
{
"code": "param2",
"value": 3
},
{
"code": "param3",
"code": "param2",
"value": 5
},
{
"code": "param3",
"value": 8
}
]
}]