diff --git a/pom.xml b/pom.xml index 0d703482..8eefb33b 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,33 @@ 17 + + + aliyun + https://maven.aliyun.com/repository/public + + true + + + true + + + + + + + + + aliyun + https://maven.aliyun.com/repository/public + + true + + + true + + + org.springframework.boot diff --git a/src/main/java/cn/lihongjie/coal/dto/CoalBlendResult.java b/src/main/java/cn/lihongjie/coal/dto/CoalBlendResult.java index a40c5eef..f50469d6 100644 --- a/src/main/java/cn/lihongjie/coal/dto/CoalBlendResult.java +++ b/src/main/java/cn/lihongjie/coal/dto/CoalBlendResult.java @@ -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 coals; + private List coals = new ArrayList<>(); private int totalCount; public String tableString() { diff --git a/src/main/java/cn/lihongjie/coal/dto/CoalInfo.java b/src/main/java/cn/lihongjie/coal/dto/CoalInfo.java index cc393d3e..6dfdb955 100644 --- a/src/main/java/cn/lihongjie/coal/dto/CoalInfo.java +++ b/src/main/java/cn/lihongjie/coal/dto/CoalInfo.java @@ -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.) + } } diff --git a/src/main/java/cn/lihongjie/coal/service/CoalService.java b/src/main/java/cn/lihongjie/coal/service/CoalService.java index 8aced3e5..f5410bed 100644 --- a/src/main/java/cn/lihongjie/coal/service/CoalService.java +++ b/src/main/java/cn/lihongjie/coal/service/CoalService.java @@ -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 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 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 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 createPercentVars(CoalBlendRequest request, CpModel model) { + int index = 0; + + List 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 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 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()) { diff --git a/src/test/resources/request1.json b/src/test/resources/request1.json index 0edf0a09..e9343505 100644 --- a/src/test/resources/request1.json +++ b/src/test/resources/request1.json @@ -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 } ] }]