Package solver.search.strategy.selectors.variables

Source Code of solver.search.strategy.selectors.variables.ActivityBased$MapVal

/*
* 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.search.strategy.selectors.variables;


import gnu.trove.list.TIntList;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntDoubleHashMap;
import gnu.trove.map.hash.TIntIntHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import solver.Solver;
import solver.exception.ContradictionException;
import solver.exception.SolverException;
import solver.explanations.Deduction;
import solver.explanations.Explanation;
import solver.search.limits.FailCounter;
import solver.search.loop.monitors.*;
import solver.search.strategy.assignments.DecisionOperator;
import solver.search.strategy.decision.Decision;
import solver.search.strategy.decision.fast.FastDecision;
import solver.search.strategy.strategy.AbstractStrategy;
import solver.variables.IVariableMonitor;
import solver.variables.IntVar;
import solver.variables.events.IEventType;
import util.PoolManager;
import util.iterators.DisposableValueIterator;

import java.util.BitSet;
import java.util.Comparator;

/**
* Implementation of the search described in:
* "Activity-Based Search for Black-Box Constraint Propagramming Solver",
* Laurent Michel and Pascal Van Hentenryck, CPAIOR12.
* <br/>
*
* @author Charles Prud'homme
* @since 07/06/12
*/
public class ActivityBased extends AbstractStrategy<IntVar> implements IMonitorDownBranch, IMonitorRestart,
        IVariableMonitor<IntVar>, Comparator<IntVar>/*, VariableSelector<IntVar>*/ {

    public static final Logger logger = LoggerFactory.getLogger("solver");

    static final double ONE = 1.0f;

    static final double[] distribution = new double[]{// two-sided 95%
            999.99d,
            12.706f, 4.303f, 3.182f, 2.776f, 2.571f, // 1...5
            2.447f, 2.365f, 2.306f, 2.262f, 2.228f// 6...10
            2.201f, 2.179f, 2.160f, 2.145f, 2.131f// 10...15
            2.120f, 2.110f, 2.101f, 2.093f, 2.086f// 16...20
            2.080f, 2.074f, 2.069f, 2.064f, 2.060f// 21...25
            2.056f, 2.052f, 2.048f, 2.045f, 2.042f// 26...30
            2.040f, 2.037f, 2.035f, 2.032f, 2.030f// 31...35
            2.028f, 2.026f, 2.024f, 2.023f, 2.021f// 36...40
            2.000f, 1.990f, 1.984f, 1.980f, 1.977f// 60, 80, 100, 120, 140
            1.975f, 1.973f, 1.972f, 1.969f, 1.960f   // 160, 180, 200, 250, inf
    };

    private static double distribution(int n) {
        if (n <= 0) {
            throw new UnsupportedOperationException();
        } else if (n > 0 && n < 41) {
            return distribution[n - 1];
        } else if (n < 61) {
            return distribution[40];
        } else if (n < 81) {
            return distribution[41];
        } else if (n < 101) {
            return distribution[42];
        } else if (n < 121) {
            return distribution[43];
        } else if (n < 141) {
            return distribution[44];
        } else if (n < 161) {
            return distribution[45];
        } else if (n < 181) {
            return distribution[46];
        } else if (n < 201) {
            return distribution[47];
        } else if (n < 251) {
            return distribution[48];
        } else {
            return distribution[49];
        }
    }

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

    final Solver solver;
    final TIntIntHashMap v2i;
    final IntVar[] vars;

    final double[] A; // activity of all variables
    final double[] mA; // the mean -- maintained incrementally
    final double[] sA; // the variance -- maintained incrementally -- std dev = sqrt(sA/path-1)
    final IVal[] vAct; // activity of each value of all variables

    final BitSet affected; // store affected variables

    final double g, d; // g for aging, d for interval size estimation
    final int a; // forget parameter
    final double r;

    public boolean sampling; // is this still in a sampling phase

    int nb_probes; // probing size

    int samplingIterationForced = 1; // CPRU: add this to force sampling phase

    java.util.Random random; //  a random object for the sampling phase

    PoolManager<FastDecision> decisionPool;

    int currentVar = -1, currentVal = -1;

    TIntList bests = new TIntArrayList();

  boolean restartAfterEachFail = true;

    public ActivityBased(final Solver solver, IntVar[] vars, double g, double d, int a, double r, int samplingIterationForced, long seed) {
        super(vars);
        this.solver = solver;
        this.vars = vars;
        A = new double[vars.length];
        mA = new double[vars.length];
        sA = new double[vars.length];
        vAct = new IVal[vars.length];
        affected = new BitSet(vars.length);

        this.v2i = new TIntIntHashMap(vars.length);
        for (int i = 0; i < vars.length; i++) {
            v2i.put(vars[i].getId(), i);
            vars[i].addMonitor(this);
        }

        assert g >= 0.0f && g <= 1.0f;
        this.g = g;
        assert d >= 0.0f && d <= 1.0f;
        this.d = d;
        assert a > 0;
        this.a = a;
        this.r = r;
        sampling = true;
        random = new java.util.Random(seed);
        nb_probes = 0;
        this.samplingIterationForced = samplingIterationForced;
//        idx_large = 0; // start the first variable
    SMF.restartAfterEachSolution(solver);
    solver.plugMonitor(new IMonitorContradiction() {
      @Override
      public void onContradiction(ContradictionException cex) {
        if(restartAfterEachFail){
          solver.getSearchLoop().restart();
        }
      }
    });

        solver.getSearchLoop().plugSearchMonitor(this);
        decisionPool = new PoolManager<FastDecision>();
//        init(vars);
    }

    @Override
    public void init() {
        for (int i = 0; i < vars.length; i++) {
            //TODO handle large domain size
            int ampl = vars[i].getUB() - vars[i].getLB() + 1;
            if (ampl > 512) {
                vAct[i] = new MapVal(vars[i].getLB());
            } else {
                vAct[i] = new ArrayVal(ampl, vars[i].getLB());
            }
        }
    }

    @Override
    public Decision<IntVar> computeDecision(IntVar variable) {
        if (variable == null || variable.isInstantiated()) {
            return null;
        }
        if (currentVar==-1 || vars[currentVar] != variable) {
      if(sampling){
        return null;
      }
            // retrieve indice of the variable in vars
      for(int i=0;i<vars.length;i++){
        if(vars[i]==variable){
          currentVar = i;
        }
      }
            assert vars[currentVar] == variable;
        }
        currentVal = variable.getLB();
        if (sampling) {
            int ds = variable.getDomainSize();
            int n = random.nextInt(ds);
            if (variable.hasEnumeratedDomain()) {
                while (n-- > 0) {
                    currentVal = variable.nextValue(currentVal);
                }
            } else {
                currentVal += n;
            }
        } else {
            if (variable.hasEnumeratedDomain()) {
                bests.clear();
                double bestVal = Double.MAX_VALUE;
                DisposableValueIterator it = variable.getValueIterator(true);
                while (it.hasNext()) {
                    int value = it.next();
                    double current = vAct[currentVar].activity(value);
                    if (current < bestVal) {
                        bests.clear();
                        bests.add(value);
                        bestVal = current;
                    } else {
                        bests.add(value);
                    }
                }
                currentVal = bests.get(random.nextInt(bests.size()));
            } else {
                int lb = variable.getLB();
                int ub = variable.getUB();
                currentVal = vAct[currentVar].activity(lb) < vAct[currentVar].activity(ub) ?
                        lb : ub;
            }
        }
        FastDecision currrent = decisionPool.getE();
        if (currrent == null) {
            currrent = new FastDecision(decisionPool);
        }
        currrent.set(variable, currentVal, DecisionOperator.int_eq);
//            System.out.printf("D: %d, %d: %s\n", currentVar, currentVal, best);
        return currrent;
    }

    @Override
    public Decision<IntVar> getDecision() {
        IntVar best = null;
        bests.clear();
        double bestVal = -1.0d;
        for (int i = 0; i < vars.length; i++) {
            int ds = vars[i].getDomainSize();
            if (ds > 1) {
                double a = A[v2i.get(vars[i].getId())] / ds;
                if (a > bestVal) {
                    bests.clear();
                    bests.add(i);
                    bestVal = a;
                } else if (a == bestVal) {
                    bests.add(i);
                }
            }
        }
        if (bests.size() > 0) {
            currentVar = bests.get(random.nextInt(bests.size()));
            best = vars[currentVar];
        }
        return computeDecision(best);
    }

    @Override
    public int compare(IntVar o1, IntVar o2) {
        if (sampling) {
            return random.nextBoolean() ? 1 : -1;
        }
        // select var with the largest ratio A(x)/|D(x)|
        int id1 = v2i.get(o1.getId());
        int id2 = v2i.get(o2.getId());
        // avoid using / operation, * is faster
        double b1 = A[id1] * o2.getDomainSize();
        double b2 = A[id2] * o1.getDomainSize();
        if (b1 > b2) {
            return -1;
        } else if (b1 < b2) {
            return 1;
        }
        return 0;
    }

    public double getActivity(IntVar var) {
        if (v2i.contains(var.getId())) {
            return A[v2i.get(var.getId())] / var.getDomainSize();
        } else {
            return 0.0d;
        }
    }


    @Override
    public void onUpdate(IntVar var, IEventType evt) {
        affected.set(v2i.get(var.getId()));
    }

    @Override
    public void explain(Deduction d, Explanation e) {
        throw new SolverException("Activity does not modify variables on IVariableMonitor.onUpdate.\n" +
                "So it cannot explain value removals.");
    }


    @Override
    public void beforeDownLeftBranch() {
        affected.clear();
    }

    @Override
    public void beforeDownRightBranch() {
    }

    @Override
    public void afterDownLeftBranch() {
        if (currentVar > -1) {  // if the decision was computed by another strategy
            for (int i = 0; i < A.length; i++) {
                if (vars[i].getDomainSize() > 1) {
                    A[i] *= sampling ? ONE : g;
                }
                if (affected.get(i)) {
                    A[i] += 1;
                }
            }
            double act = vAct[currentVar].activity(currentVal);
            if (sampling) {
                vAct[currentVar].setactivity(currentVal, act + affected.cardinality());
            } else {
                vAct[currentVar].setactivity(currentVal, (act * (a - 1) + affected.cardinality()) / a);
            }
            currentVar = -1;
        }
    }

    @Override
    public void afterDownRightBranch() {
    }

    @Override
    public void beforeRestart() {
    }

    @Override
    public void afterRestart() {
        if (sampling) {
            nb_probes++;
            for (int i = 0; i < A.length; i++) {
                double activity = A[i];
                double oldmA = mA[i];

                double U = activity - oldmA;
                mA[i] += (U / nb_probes);
                sA[i] += (U * (activity - mA[i]));
                A[i] = 0;
                vAct[i].update(nb_probes);
            }
            // check if sampling is still required
//            logger.info("<<<<START check");
            int idx = 0;
            while (idx < vars.length && checkInterval(idx)) {
                idx++;
//                logger.info("inc {}", idx);
            }
//            logger.info(">>>>END check");
            //BEWARE: when it fails very soon (after 1 node), it worths forcing sampling
            if (nb_probes > samplingIterationForced && idx == vars.length) {
                if (logger.isInfoEnabled()) {
                    solver.getMeasures().updateTimeCount();
                    //logger.info(">> STOP SAMPLING: {}", solver.getMeasures().toOneShortLineString());
                    //logger.info(">> {}", Arrays.toString(mA));
                }
                sampling = false;
                restartAfterEachFail = false;
                // then copy values estimated
                System.arraycopy(mA, 0, A, 0, mA.length);
                for (int i = 0; i < A.length; i++) {
                    vAct[i].transfer();
                }
//                solver.getSearchLoop().restartAfterEachSolution(false);
                SearchMonitorFactory.geometrical(solver, 3 * vars.length, r,
                        new FailCounter(3 * vars.length), Integer.MAX_VALUE);

            }
        }
    }

    /**
     * Return true if the interval is small enough
     *
     * @param idx idx of the variable to check
     * @return true if the confidence interval is small enough, false otherwise
     */
    private boolean checkInterval(int idx) {
        if (!vars[idx].isInstantiated()) {
            double stdev = Math.sqrt(sA[idx] / (nb_probes - 1));
            double a = distribution(nb_probes) * stdev / Math.sqrt(nb_probes);
//            logger.info("m: {}, v: {}, et: {} => {}", new Object[]{mA[idx], sA[idx], stdev, (a / mA[idx])});
            return (a / mA[idx]) < d;
        }
        return true;
    }

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

    private static interface IVal {

        double activity(int value);

        void setactivity(int value, double activity);

        void update(int nb_probes);

        void transfer();
    }

    private static final class ArrayVal implements IVal {

        final double[] Av;
        final double[] mAv;
        final int size;
        final int os;  // offset

        private ArrayVal(int size, int os) {
            this.size = size;
            this.os = os;
            this.Av = new double[size];
            this.mAv = new double[size];
        }

        @Override
        public double activity(int value) {
            return Av[value - os];
        }


        @Override
        public void setactivity(int value, double activity) {
            Av[value - os] = activity;
        }

        @Override
        public void update(int nb_probes) {
            double activity, oldmA, U;
            for (int j = 0; j < Av.length; j++) {
                activity = Av[j];
                oldmA = mAv[j];
                U = activity - oldmA;
                mAv[j] += (U / nb_probes);
            }
        }

        @Override
        public void transfer() {
            System.arraycopy(mAv, 0, Av, 0, size);
        }
    }

    private static final class MapVal implements IVal {

        final TIntDoubleHashMap Av;
        final TIntDoubleHashMap mAv;
        final int os;  // offset

        private MapVal(int os) {
            this.os = os;
            this.Av = new TIntDoubleHashMap(32, 0.5f, 0, 0);
            this.mAv = new TIntDoubleHashMap(32, 0.5f, 0, 0);
        }

        @Override
        public double activity(int value) {
            return Av.get(value - os);
        }

        @Override
        public void setactivity(int value, double activity) {
            Av.put(value - os, activity);
        }

        @Override
        public void update(int nb_probes) {
            double activity, oldmA, U;
            int[] keys = Av.keys();
            for (int j = 0; j < keys.length; j++) {
                int k = keys[j];
                activity = Av.get(k);
                oldmA = mAv.get(k);
                U = activity - oldmA;
                mAv.adjustValue(k, U / nb_probes);
            }
        }

        @Override
        public void transfer() {
            Av.clear();
            Av.putAll(mAv);
        }
    }

}
TOP

Related Classes of solver.search.strategy.selectors.variables.ActivityBased$MapVal

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.