Search code examples
constraintsadditiondroolsrulesoptaplanner

Remove/Add constraints - optaplanner


Is it possible to make some rules be completely ignored? I have a set of rules, but I want the user to be able to add certain inputs, like they want rule 1, rule 2, rule 3, rule 5, but maybe not rule 4. So I want the program to recognise this, and not at all enter rule 4 while checking for constraint violation

How could I go about this?


Solution

  • I've got a similar problem, except that I wanted users to control each rule weight [0 to 10] instead of a binary control [active - inactive]. I'm not sure about this being a performance optimized answer (worked for me in reasonable time, but of course that depends on your corpus size).

    The approach we used was creating a Singleton which holds each rule weight set by the user in volatile memory, using a HashMap<Integer, Integer> for faster random access (key = rule number, value = rule weight), as the inference engine may call it several times.

    Then, in our rule files we checked if a given rule was active in when clause, and updated score in then clause according to the actual rule weight:

    import my.rules.singleton.package.MyRulesWeightSingleton;
    
    rule "1"
        when
            eval(MyRulesWeightSingleton.isRuleActive(1))
            //other conditions here.
        then
            scoreHolder.addHardConstraintMatch(kcontext, MyRulesWeightSingleton.getRuleWeight(1));
    end
    

    The Singleton would look like this:

    import java.util.HashMap;
    
    public class MyRulesWeightSingleton {
    
        private static MyRulesWeightSingleton instance;
        private HashMap<Integer, Integer> weights;
    
        private MyRulesWeightSingleton() {
            this.weights = new HashMap<Integer, Integer>();
        }
    
        public static MyRulesWeightSingleton getInstance() {
            if (instance == null) {
                instance = new MyRulesWeightSingleton();
            }
            return instance;
        }
    
        public boolean isRuleActive(int ruleId) {
            Integer weight = weights.get(ruleId);
            return (weight != null && weight > 0);
        }
    
        public int getRuleWeight(int ruleId) {
            Integer weight = weights.get(ruleId);
            if (weight != null) {
                return weight;
            }
            return 0;
        }
    
        //Allows you to put and remove weights information
        //before running planner.
        public HashMap<Integer, Integer> getWeights() {
            return this.weights;
        }
    }
    

    PS: Our actual problem here was a bit more complicated than this, so I simplified our approach for didatical reasons. ;)