Package solver.explanations

Source Code of solver.explanations.RecorderExplanationEngine

/*
* Copyright (c) 1999-2014, Ecole des Mines de Nantes
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the Ecole des Mines de Nantes nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package solver.explanations;

import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.set.hash.TIntHashSet;
import solver.Configuration;
import solver.ICause;
import solver.Solver;
import solver.constraints.Propagator;
import solver.exception.SolverException;
import solver.explanations.antidom.AntiDomain;
import solver.search.loop.monitors.IMonitorInitPropagation;
import solver.search.strategy.decision.Decision;
import solver.variables.BoolVar;
import solver.variables.IntVar;
import solver.variables.Variable;
import util.objects.queues.CircularQueue;

/**
* Created by IntelliJ IDEA.
* User: njussien
* Date: 26 oct. 2010
* Time: 14:18:18
* <p/>
* An RecorderExplanationEngine is used to record explanations throughout computation.
* Here we just record the explanations in a HashMap ...
* <p/>
*/
public class RecorderExplanationEngine extends ExplanationEngine implements IMonitorInitPropagation {

    TIntObjectHashMap<AntiDomain> removedvalues; // maintien du domaine courant
    TIntObjectHashMap<TIntObjectHashMap<ValueRemoval>> valueremovals; // maintain deduction base
    // maintain cause of propagator activation -- can be sparse
    TIntObjectHashMap<PropagatorActivation> propactivs;
    TIntObjectHashMap<Explanation> database; // base d'explications

    TIntObjectHashMap<TIntObjectHashMap<BranchingDecision>> leftbranchdecisions; // maintien de la base de left BranchingDecision
    TIntObjectHashMap<TIntObjectHashMap<BranchingDecision>> rightbranchdecisions; // maintien de la base de right BranchingDecision

    protected TIntHashSet expanded = new TIntHashSet();
    protected TIntHashSet toexpand = new TIntHashSet();
    protected CircularQueue<Deduction> pending = new CircularQueue<>(16);

    public RecorderExplanationEngine(Solver solver) {
        super(solver);
        if (!Configuration.PLUG_EXPLANATION) {
            throw new SolverException("\nExplanations are not plugged in.\n" +
                    "To activate explanations, create a user.property file at project root directory " +
                    "which contains the following two lines:\n" +
                    "# Enabling explanations:\n" +
                    "PLUG_EXPLANATION=true\n");
        }
        removedvalues = new TIntObjectHashMap<>();
        valueremovals = new TIntObjectHashMap<>();
        propactivs = new TIntObjectHashMap<>();
        database = new TIntObjectHashMap<>();
        leftbranchdecisions = new TIntObjectHashMap<>();
        rightbranchdecisions = new TIntObjectHashMap<>();
        solver.plugMonitor(this);
    }

    @Override
    public boolean isActive() {
        return true;
    }

    @Override
    public void beforeInitialPropagation() {
        for (Variable v : solver.getVars()) {
            getRemovedValues((IntVar) v);
        }
    }

    @Override
    public void afterInitialPropagation() {
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public AntiDomain getRemovedValues(IntVar v) {
        int vid = v.getId();
        AntiDomain toreturn = removedvalues.get(vid);
        if (toreturn == null) {
            toreturn = v.antiDomain();
            removedvalues.put(vid, toreturn);
            TIntObjectHashMap<ValueRemoval> hm = valueremovals.get(vid);
            if (hm == null) {
                hm = new TIntObjectHashMap<>();
                valueremovals.put(vid, hm);
            }
        }
        return toreturn;
    }

    @Override
    public Explanation retrieve(IntVar var, int val) {
        return database.get(getValueRemoval(var, val).id);
    }

    public ValueRemoval getValueRemoval(IntVar var, int val) {
        int vid = var.getId();
        ValueRemoval vr;
        TIntObjectHashMap<ValueRemoval> hm = valueremovals.get(vid);
        if (hm == null) {
            hm = new TIntObjectHashMap<>();
            valueremovals.put(vid, hm);
        }
        vr = hm.get(val);
        if (vr == null) {
            vr = new ValueRemoval(var, val);
            valueremovals.get(vid).put(val, vr);
        }
        return vr;
    }

    @Override
    public PropagatorActivation getPropagatorActivation(Propagator propagator) {
//        assert propagator.isActive();
        int pid = propagator.getId();
        PropagatorActivation pa;
        pa = propactivs.get(pid);
        if (pa == null) {
            pa = new PropagatorActivation(propagator);
            propactivs.put(pid, pa);
        }
        return pa;
    }

    @Override
    public BranchingDecision getDecision(Decision decision, boolean isLeft) {
        int vid = decision.getDecisionVariable().getId();
        TIntObjectHashMap<BranchingDecision> mapvar = isLeft ? leftbranchdecisions.get(vid) : rightbranchdecisions.get(vid);
        BranchingDecision vr;
        if (mapvar == null) {
            mapvar = new TIntObjectHashMap<>();
            if (isLeft) {
                if (!decision.hasNext()) {
                    System.out.println(decision);
                    throw new SolverException("Arg!");
                }
                leftbranchdecisions.put(vid, mapvar);
            } else {
                rightbranchdecisions.put(vid, mapvar);
            }
        }
        vr = mapvar.get(decision.getId());
        if (vr == null) {
            vr = new BranchingDecision(decision, isLeft);
            mapvar.put(decision.getId(), vr);
        }
        return vr;
    }

    @Override
    public void store(Deduction deduction, Explanation explanation) {
        database.put(deduction.id, explanation);
    }

    @Override
    public void removeLeftDecisionFrom(Decision decision, Variable var) {
        leftbranchdecisions.get(var.getId()).remove(decision.getId());
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////// ACTIONS ON VARIABLE MODIFICATIONS ///////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public void activePropagator(BoolVar var, Propagator propagator) {
        PropagatorActivation pa = getPropagatorActivation(propagator);
        Explanation expl = database.get(pa.id);
        if (expl == null) {
            expl = new Explanation();
        } else {
            expl.reset();
        }
        var.explain(VariableState.DOM, expl);
        if (Configuration.PRINT_EXPLANATION && LOGGER.isInfoEnabled()) {
            onActivatePropagator(propagator, expl);
        }
        store(pa, expl);
    }


    private void explainValueRemoval(IntVar var, int val, ICause cause) {
        // 1. retrieve the deduction
        Deduction vr = getValueRemoval(var, val);
        // 2. get the previous explanation, if any
        Explanation expl = database.get(vr.id);
        if (expl == null) {
            expl = new Explanation();
            store(vr, expl);
        } else {
            expl.reset();
        }
        // 3. explain the value removal thanks to the cause
        cause.explain(vr, expl);
        // 4. explanations monitoring
        if (Configuration.PRINT_EXPLANATION && LOGGER.isInfoEnabled()) {
            onRemoveValue(var, val, cause, expl);
        }
    }

    @Override
    public void removeValue(IntVar var, int val, ICause cause) {
        assert cause != null;
        // 1. explain the value removal
        explainValueRemoval(var, val, cause);
        // 2. update the inverse domain
        AntiDomain invdom = getRemovedValues(var);
        invdom.add(val);
    }

    @Override
    public void updateLowerBound(IntVar var, int old, int val, ICause cause) {
        assert cause != null;
        AntiDomain invdom = getRemovedValues(var);
        if (invdom.isEnumerated()) {
            for (int v = old; v < val; v++) {
                if (!invdom.get(v)) {
                    explainValueRemoval(var, v, cause);
                    invdom.add(v);
                }
            }
        } else {
            // PREREQUISITE: val is the new LB, so val-1 is the one explained
            val--;
            if (!invdom.get(val)) {
                explainValueRemoval(var, val, cause);
                // we add +1, because val is the value just BEFORE the new LB
                invdom.updateLowerBound(old, val + 1);
            }
        }
    }

    @Override
    public void updateUpperBound(IntVar var, int old, int val, ICause cause) {
        assert cause != null;
        AntiDomain invdom = getRemovedValues(var);
        if (invdom.isEnumerated()) {
            for (int v = old; v > val; v--) {
                if (!invdom.get(v)) {
                    explainValueRemoval(var, v, cause);
                    invdom.add(v);
                }
            }
        } else {
            // PREREQUISITE: val is the new UB, so val+1 is the one explained
            val++;
            if (!invdom.get(val)) {
                explainValueRemoval(var, val, cause);
                // we add -1, because val is the value just AFTER the new LB
                invdom.updateUpperBound(old, val - 1);
            }
        }
    }


    @Override
    public void instantiateTo(IntVar var, int val, ICause cause, int oldLB, int oldUB) {
        AntiDomain invdom = getRemovedValues(var);

        if (invdom.isEnumerated()) {
            for (int v = oldLB; v < val; v++) {
                if (!invdom.get(v)) {
                    explainValueRemoval(var, v, cause);
                    invdom.add(v);
                }
            }
            for (int v = oldUB; v > val; v--) {
                if (!invdom.get(v)) {
                    explainValueRemoval(var, v, cause);
                    invdom.add(v);
                }
            }
        } else {
            if (val < oldLB) {
                // domain wipe out
                explainValueRemoval(var, oldLB, cause);
                invdom.updateUpperBound(oldUB, oldLB - 1);
            } else if (val > oldUB) {
                // domain wipe out
                explainValueRemoval(var, oldUB, cause);
                invdom.updateLowerBound(oldLB, oldUB + 1);
            } else {
                if (val > oldLB && !invdom.get(val)) {
                    explainValueRemoval(var, val - 1, cause);
                    invdom.updateLowerBound(oldLB, val);
                }
                if (val < oldUB && !invdom.get(val)) {
                    explainValueRemoval(var, val + 1, cause);
                    invdom.updateUpperBound(oldUB, val);
                }
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    @Override
    public Explanation flatten(Explanation expl) {
        Explanation toreturn = new Explanation();


        expanded.clear();
        toexpand.clear();
        pending.clear();

        Deduction ded;
        int nbd = expl.nbDeductions();
        for (int i = 0; i < nbd; i++) {
            ded = expl.getDeduction(i);
            pending.addLast(ded);
            toexpand.add(ded.id);
        }


        while (!pending.isEmpty()) {
            ded = pending.pollFirst();
            toexpand.remove(ded.id);
            expanded.add(ded.id);

            Explanation e = database.get(ded.id);
//            System.out.printf("%s \n", ded);
            if (e != null) {
                int nbp = e.nbPropagators();
                for (int i = 0; i < nbp; i++) {
                    toreturn.add(e.getPropagator(i));
                }
                nbd = e.nbDeductions();
                for (int i = 0; i < nbd; i++) {
                    ded = e.getDeduction(i);
//                    System.out.printf("\t-> %s\n", ded);
                    if (!expanded.contains(ded.id) && toexpand.add(ded.id)) {
                        pending.addLast(ded);
                    }
                }
            } else {
                toreturn.add(ded);
            }
//            System.out.printf("\n");
        }
        return toreturn;
    }

    @Override
    public Explanation flatten(IntVar var, int val) {
        // TODO check that it is always called with val NOT in var
        AntiDomain ad = getRemovedValues(var);
        return flatten(getValueRemoval(var, ad.getKeyValue(val)));
    }

    @Override
    public Explanation flatten(Deduction deduction) {
        Explanation expl = new Explanation();
        expl.add(deduction);
        return flatten(expl);
    }

    @Override
    public Deduction explain(IntVar var, int val) {
        AntiDomain ad = getRemovedValues(var);
        return explain(getValueRemoval(var, ad.getKeyValue(val)));
    }

    @Override
    public Deduction explain(Deduction deduction) {
        return deduction;
    }
}
TOP

Related Classes of solver.explanations.RecorderExplanationEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.