约束满足问题(Constraint Satisfaction Problem, CSP)的Java实现(二)问题的定义

约束满足问题(Constraint Satisfaction Problem, CSP)的Java实现(二)问题的定义

接上篇,我们开始直接代码部分的工作,首先是问题的定义,对于一个约束,我们有一个基类如下所示:

import java.util.ArrayList;
import java.util.List;

public class AbstractConstraint<V,C> {
    List<V> variableList;

    public AbstractConstraint(){
        variableList = new ArrayList<>();
    }

    public AbstractConstraint(List<V> variables){
        variableList = new ArrayList<>();
        variableList.addAll(variables);
    }

    boolean satisfied(AbstractAssignment<V,C> assignment){
        return true;
    }
}

同理,定义一个抽象的解类,有

import java.util.HashMap;
import java.util.Map;

public class AbstractAssignment<V,D> {
    Map<V,D> ass;
    public AbstractAssignment(){
        ass = new HashMap<>();
    }

    public AbstractAssignment(AbstractAssignment<V,D> input){
        ass = new HashMap<>(input.getContents());
    }

    D getDomain(V v) {
        return ass.get(v);
    }

    int getSize(){
        return ass.size();
    }

    boolean hasVariable(V v){
        return ass.containsKey(v);
    }

    void put(V v,D d){
        ass.put(v,d);
    }

    void remove(V v){
        ass.remove(v);
    }

    void display(){
        for(Map.Entry<V,D> entry:ass.entrySet()){
            System.out.println(entry.getKey().toString()+" "+entry.getValue().toString());
        }
    }

    Map<V,D> getContents(){
        return ass;
    }
}

对于CSP问题,我们首先定义一个接口,这个接口包含了添加约束,验证是否合格,回溯求解等函数。

import java.util.List;
import java.util.Map;

public interface Solvable<V,D> {
    void addConstraint(AbstractConstraint<V,D> constraint) throws Exception;
    boolean consistent(V v, AbstractAssignment<V,D> assignment);
    boolean backTracking(AbstractAssignment<V,D> assignment, Map<V, List<D>> domains);
    AbstractAssignment<V,D> backTrackingSearch();
    List<V> selectUnassignedVariable(List<V> unassigned);
}

CSP问题求解有一个基本的实现,如下

import java.util.*;

public class ClassicCSP<V,D> implements Solvable<V,D>{
    List<V> variables;
    Map<V, List<D>> domains;
    Map<V, List<AbstractConstraint<V,D>>> constraints;
    List<Oder<V,D>> oderAlgorithmList;
    List<Inference<V,D>> inferenceList;

    public ClassicCSP(List<V> vars, Map<V, List<D>> doms) throws Exception {
        variables = new ArrayList<>();
        constraints = new HashMap<>();
        domains = new HashMap<>();
        variables.addAll(vars);
        domains.putAll(doms);
        oderAlgorithmList = new ArrayList<>();
        inferenceList = new ArrayList<>();
        for(V v : variables){
            if(!domains.containsKey(v)){
                throw new Exception("The domain do not contain variable! Variable is "+v.toString());
            }
        }
    }

    public void addOderAlgorithm(Oder<V,D> oder){
        oderAlgorithmList.add(oder);
    }

    public void addInferenceAlgorithm(Inference<V,D> inf) { inferenceList.add(inf); }

    @Override
    public void addConstraint(AbstractConstraint<V, D> constraint) throws Exception {
        for(V v: constraint.variableList){
            if(!variables.contains(v)){
                throw  new Exception("The variable in constraint is not in the CSP! Variable is "+v.toString());
            }
            else{
                if(constraints.containsKey(v)){
                    constraints.get(v).add(constraint);
                }
                else{
                    constraints.put(v,new ArrayList<AbstractConstraint<V,D>>(Arrays.asList(constraint)));
                }
            }
        }
    }

    @Override
    public boolean consistent(V v, AbstractAssignment<V, D> assignment) {
        if(constraints.get(v)!=null){
            for(AbstractConstraint<V,D> constraint: constraints.get(v)){
                if(!constraint.satisfied(assignment)){
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public boolean backTracking(AbstractAssignment<V, D> assignment, Map<V, List<D>> domains) {
        if(assignment.getSize()==variables.size()){
            return true;
        }
        List<V> unassigned = new ArrayList<>();
        for(V variable:variables){
            if(!assignment.hasVariable(variable)){
                unassigned.add(variable);
            }
        }
        //order the variable!
        for(Oder<V,D> oder:oderAlgorithmList){
            boolean result = oder.oderUnassigned(unassigned, assignment, domains, constraints);
            if(!result){
                return false;
            }
        }
        V firstVariable = unassigned.get(0);
        unassigned.remove(firstVariable);
        //order the variable!

        for(D domain:domains.get(firstVariable)){
            //to avoid operate on the same list, we need to deep copy
            Map<V, List<D>> domainsBackend = new HashMap<>();
            for(Map.Entry<V,List<D>> entry:domains.entrySet()){
                domainsBackend.put(entry.getKey(),new ArrayList<>(entry.getValue()));
            }

            assignment.put(firstVariable, domain);
            //inference!
            if(consistent(firstVariable, assignment)){
                for(Inference<V,D> infer:inferenceList){
                    infer.doInference(unassigned,assignment,domainsBackend,constraints);
                }
                //update the domain
                for(V v:unassigned){
                    if(!v.equals(firstVariable)){
                        //get the variables not assigned
                        //get the variable that have constraint with firstVariable
                        for(AbstractConstraint<V,D> constraint:constraints.get(firstVariable)){
                            if(constraint.variableList.contains(v)){
                                for(D targetDomain:domains.get(v)){
                                    AbstractAssignment<V,D> tempAssignment = new AbstractAssignment<>(assignment);
                                    tempAssignment.put(v, targetDomain);
                                    if(!consistent(firstVariable, tempAssignment)){
                                        domainsBackend.get(v).remove(targetDomain);
                                    }
                                }
                            }
                        }
                    }
                }
                boolean haveResult = backTracking(assignment, domainsBackend);
                if(haveResult){
                    return true;
                }
            }
            assignment.remove(firstVariable);
        }
        return false;
    }

    @Override
    public AbstractAssignment<V, D> backTrackingSearch() {
        AbstractAssignment<V,D> result = new AbstractAssignment<>();
        boolean haveResult = backTracking(result, domains);
        if(haveResult){
            return result;
        }
        else{
            return null;
        }
    }

    @Override
    public List<V> selectUnassignedVariable(List<V> unassigned) {
        return null;
    }
}

注意在这里,Inference和变量的排序都没有实现,我们通过装饰器模式讲这些功能灵活地加入CSP求解器中,具体如何实现看下一章。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值