PlanningSolution类讲解

内容概要
通过这篇文章,我们来学习将ProblemFact、PlanningEntity连接在一起以及负责与OptaPlanner交互的Solution类。
ProblemFact实例
一个规划问题的数据集需要被包含在一个类中,供求解器求解。该解决方案类同时代表了规划问题和(求解结束后)解决方案。它被注解为​​@PlanningSolution​​注解。 例如,云资源优化的例子中,解决方案类是​​CloudBalance​​类,它包含一个​​computerList​​列表,一个​​processList​​列表。

@PlanningSolution
@XStreamAlias("CloudBalance")
public class CloudBalance extends AbstractPersistable {
    private List<CloudComputer> computerList;
    private List<CloudProcess> processList;
    ......
}

一个规划问题实际上是一个未解决的规划解决方案,或者换个说法,一个未初始化的解决方案。

例如,在云资源优化例子中,那个​​CloudBalance​​类有​​@PlanningSolution​​注解,然而未解决的​​processList​​类中的每个​​CloudProcess​​都还没有被分配到一个计算机(他们的​​computer​​属性为空)。这不是一个可行的解决方案,它甚至不是一个可能的解决方案,这是一个未初始化的解决方案。


Solution类
一个​​Solution​​类持有所有的​​ProblemFact​​、​​PlanningEntity​​和一个​​Score​​。添加​​@PlanningSolution​​注解。例如,一个​​loudBalance​​实例持有所有计算机、进程的列表。

@PlanningSolution
@XStreamAlias("CloudBalance")
public class CloudBalance extends AbstractPersistable {
    private List<CloudComputer> computerList;
    private List<CloudProcess> processList;
    ......
}

求解器配置需要声明规划解决方案类:

<solver xmlns="https://www.optaplanner.org/xsd/solver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd">
  ...
  <solutionClass>org.optaplanner.examples.nqueens.domain.NQueens</solutionClass>
  ...
</solver>

Solution中的PlanningEntity
OptaPlanner需要从​​Solution实例​​中提取​​PlanningEntity​​实例。它通过调用每一个被​​@PlanningEntityCollectionProperty​​注释的​​getter​​(或字段)来获得这些集合。

@PlanningSolution
public class NQueens {
    ...

    private List<Queen> queenList;

    @PlanningEntityCollectionProperty
    public List<Queen> getQueenList() {
        return queenList;
    }

}

可以有多个​​@PlanningEntityCollectionProperty​​注解的属性。那些甚至可以返回一个具有相同实体类类型的集合,也可以返回一个数组。

@PlanningEntityCollectionProperty注解需要在具有@PlanningSolution注解的类中的一个属性上。它在没有该注解的父类或子类中被忽略。

在极少数情况下,一个规划实体可能是一个属性:在其​​getter​​方法(或字段)上使用​​@PlanningEntityProperty​​来代替。如果启用,这两个注解也可以被自动发现。


Solution中的Score
一个​​@PlanningSolution类​​需要一个分数属性(或字段),需要添加​​@PlanningScore注解​​。如果分数还没有被计算,那么分数属性就是空的。分数属性的类型与你的用例的具体分数实现有关。例如,​​NQueens​​使用一个​​SimpleScore​​,​​CloudBalance​​使用的是​​HardSoftScore​​。前端培训

@PlanningSolution
public class NQueens {
    ...

    private SimpleScore score;

    @PlanningScore
    public SimpleScore getScore() {
        return score;
    }
    public void setScore(SimpleScore score) {
        this.score = score;
    }

}

大多数用例都使用​​HardSoftScore​​:

@PlanningSolution
public class CloudBalance {
    ...

    private HardSoftScore score;

    @PlanningScore
    public HardSoftScore getScore() {
        return score;
    }

    public void setScore(HardSoftScore score) {
        this.score = score;
    }

}

有些用例会使用其他分数类型。


Solution中的ProblemFact
对于约束流和Drools分数计算,OptaPlanner需要从​​Solution实例​​中提取​​ProblemFact实例​​。它通过调用每一个带有​​@ProblemFactCollectionProperty​​注解的方法(或字段)来获得这些集合。所有由这些方法返回的对象都可以被约束流或Drools规则所使用。例如,在CloudBalance中,所有的​​computerList​​是问题事实。

@PlanningSolution
@XStreamAlias("CloudBalance")
public class CloudBalance extends AbstractPersistable {

    private List<CloudComputer> computerList;

    private List<CloudProcess> processList;

    @XStreamConverter(HardSoftScoreXStreamConverter.class)
    private HardSoftScore score;

    public CloudBalance() {
    }

    public CloudBalance(long id, List<CloudComputer> computerList, List<CloudProcess> processList) {
        super(id);
        this.computerList = computerList;
        this.processList = processList;
    }

    @ValueRangeProvider(id = "computerRange")
    @ProblemFactCollectionProperty
    public List<CloudComputer> getComputerList() {
        return computerList;
    }

    public void setComputerList(List<CloudComputer> computerList) {
        this.computerList = computerList;
    }

    @PlanningEntityCollectionProperty
    public List<CloudProcess> getProcessList() {
        return processList;
    }
}

所有的​​ProblemFact​​都会自动插入到Drools工作存内存,请注意在它们的属性上添加注解。

而且可以有多个​​@ProblemFactCollectionProperty​​注解的成属性。这些属性甚至可以返回具有相同类别类型的集合,但它们不应该两次返回相同的实例,它也可以返回一个数组。

@ProblemFactCollectionProperty注解需要在一个有@PlanningSolution注解的类中的成员上。它在父类或没有该注解的子类上会被忽略。

在极少数情况下,ProblemFact可能是一个对象:在其方法(或字段)上使用​​@ProblemFactProperty​​代替。


扩展ProblemFact
有些​​ProblemFact​​一开始并未在业务模型中的体现,但是这些​​ProblemFact​​数据可以简化约束规则的编写,在提交求解之前,将这些数据计算出来作为一个​​ProblemFact​​放在​​Solution类​​内,可以是求解器更快、更简单的进行求解。

例如,在考试中,每两个至少共享一个学生的考试科目,就会创建一个的​​ProblemFact​​问题事实​​TopicConflict​​。

   @ProblemFactCollectionProperty
    private List<TopicConflict> calculateTopicConflictList() {
        List<TopicConflict> topicConflictList = new ArrayList<TopicConflict>();
        for (Topic leftTopic : topicList) {
            for (Topic rightTopic : topicList) {
                if (leftTopic.getId() < rightTopic.getId()) {
                    int studentSize = 0;
                    for (Student student : leftTopic.getStudentList()) {
                        if (rightTopic.getStudentList().contains(student)) {
                            studentSize++;
                        }
                    }
                    if (studentSize > 0) {
                        topicConflictList.add(new TopicConflict(leftTopic, rightTopic, studentSize));
                    }
                }
            }
        }
        return topicConflictList;
    }

当分数约束需要检查是否有两个具有共同学生的题目的考试被安排在一起(取决于约束:在同一时间,在一排,或在同一天),​​TopicConflict​​实例可以被用作问题事实,而不是必须结合每两个学生实例,在求解过程中去计算,这样会大大降低OptaPlanner求解的效率。


自动扫描属性
与其明确配置每个属性(或字段)注解,有些也可以由OptaPlanner自动推导出来。例如,在CloudBalance的例子中:

@PlanningSolution(autoDiscoverMemberType = AutoDiscoverMemberType.FIELD)public class CloudBalance {

    // 自动发现为  @ProblemFactCollectionProperty
    @ValueRangeProvider(id = "computerRange") // Not (yet) auto discovered
    private List<CloudComputer> computerList;

    // 自动发现为  @PlanningEntityCollectionProperty
    private List<CloudProcess> processList;

    // 自动发现为 @PlanningScore
    private HardSoftScore score;

    ...
}

​​AutoDiscoverMemberType​​支持:

NONE:没有自动发现。
FIELD:自动发现​​@PlanningSolution​​类中的所有字段。
GETTER:自动发现​​@PlanningSolution​​类上的所有​​getter​​。
自动注解是基于字段类型(或​​getter​​返回类型):

​​@ProblemFactProperty​​:当它不是一个集合、一个数组、一个​​@PlanningEntity​​类或一个分数时。
​​@ProblemFactCollectionProperty​​:当它是一个不是​​@PlanningEntity​​类的集合(或数组)的类型时。
​​@PlanningEntityProperty​​:当它是一个配置的​​@PlanningEntity​​类或子类时。
​​@PlanningEntityCollectionProperty​​:当它是一个类型为配置的​​@PlanningEntity​​类或子类的集合(或数组)。
​​@PlanningScore​​:当它是一个分数或子类时。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值