Commit 86301bdd authored by Charles Vernerey's avatar Charles Vernerey
Browse files

Use Chocotools Pareto Maximizer instead of the previous one

parent 4466692d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@
        <dependency>
            <groupId>io.gitlab.chaver</groupId>
            <artifactId>chocotools</artifactId>
            <version>1.0.7</version>
            <version>1.1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
+0 −100
Original line number Diff line number Diff line
package io.gitlab.chaver.mining.patterns.constraints;

import io.gitlab.chaver.mining.patterns.io.Pattern;
import io.gitlab.chaver.mining.patterns.search.loop.monitors.PatternSearchMonitor;
import org.chocosolver.solver.constraints.Propagator;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ESat;

import java.util.List;

/**
 * Pareto global constraint : Ensures that next solution is not dominated by any pattern in the archive
 */
public class ParetoPatternMaximizer extends Propagator<IntVar> {

    private IntVar[] objectives;
    private List<Pattern> archive;

    public ParetoPatternMaximizer(IntVar[] objectives, PatternSearchMonitor monitor) {
        super(objectives);
        this.objectives = objectives;
        this.archive = monitor.getPatterns();
    }

    /**
     * Compute dominated point for objective i,
     *  i.e. DP_i = (obj_1_max,...,obj_i_min,...,obj_m_max)
     * @param i index of the variable
     * @return dominated point
     */
    private int[] computeDominatedPoint(int i) {
        int[] DP = new int[objectives.length];
        for (int j = 0; j < objectives.length; j++) {
            IntVar currentVar = objectives[j];
            DP[j] = j == i ? currentVar.getLB() : currentVar.getUB();
        }
        return DP;
    }

    /**
     * Compute tightest point for objective i
     *  i.e. the point that dominates DP_i and has the biggest obj_i
     * @param i index of the variable
     */
    private void computeTightestPoint(int i) throws ContradictionException {
        boolean tightestPointFound = false;
        int tightestPoint = 0;
        int[] dominatedPoint = computeDominatedPoint(i);
        for (Pattern p : archive) {
            int[] sol = p.getMeasures();
            int dominates = dominates(sol, dominatedPoint, i);
            if (dominates > 0) {
                int currentPoint = dominates == 1 ? sol[i] : sol[i] + 1;
                if (! tightestPointFound || tightestPoint < currentPoint) {
                    tightestPointFound = true;
                    tightestPoint = currentPoint;
                }
            }
        }
        if (tightestPointFound) {
            objectives[i].updateLowerBound(tightestPoint, this);
        }
    }

    /**
     * Return an int :
     *  0 if a doesn't dominate b
     *  1 if a dominates b and a = b if we don't take into account index i
     *  2 if a dominates b and a dominates b if we don't take into account index i
     * @param a vector
     * @param b vector
     * @param i index
     * @return an int representing the fact that a dominates b
     */
    private int dominates(int[] a, int[] b, int i) {
        int dominates = 0;
        for (int j = 0; j < objectives.length; j++) {
            if (a[j] < b[j]) return 0;
            if (a[j] > b[j]) {
                if (dominates == 0) dominates = 1;
                if (j != i) dominates = 2;
            }
        }
        return dominates;
    }


    @Override
    public void propagate(int evtmask) throws ContradictionException {
        for (int i = 0; i < objectives.length; i++) {
            computeTightestPoint(i);
        }
    }

    @Override
    public ESat isEntailed() {
        return ESat.TRUE;
    }
}
+17 −10
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@ package io.gitlab.chaver.mining.patterns.problems;
import io.gitlab.chaver.chocotools.problem.BuildModelException;
import io.gitlab.chaver.chocotools.problem.ChocoProblem;
import io.gitlab.chaver.chocotools.problem.SetUpException;
import io.gitlab.chaver.mining.patterns.constraints.ParetoPatternMaximizer;
import io.gitlab.chaver.chocotools.search.loop.monitors.SolutionRecorderMonitor;
import io.gitlab.chaver.chocotools.util.ISolutionProvider;
import io.gitlab.chaver.mining.patterns.io.DatReader;
import io.gitlab.chaver.mining.patterns.io.Database;
import io.gitlab.chaver.mining.patterns.io.Pattern;
@@ -12,9 +13,10 @@ import io.gitlab.chaver.mining.patterns.measure.Measure;
import io.gitlab.chaver.mining.patterns.measure.attribute.*;
import io.gitlab.chaver.mining.patterns.measure.operand.MeasureOperand;
import io.gitlab.chaver.mining.patterns.measure.pattern.*;
import io.gitlab.chaver.mining.patterns.search.loop.monitors.PatternSearchMonitor;
import io.gitlab.chaver.mining.patterns.search.loop.monitors.SkypatternMonitor;
import io.gitlab.chaver.mining.patterns.search.strategy.selectors.variables.MinCov;
import io.gitlab.chaver.mining.patterns.util.MeasureListConverter;
import io.gitlab.chaver.mining.patterns.util.PatternCreator;
import io.gitlab.chaver.mining.patterns.util.TransactionGetter;
import org.chocosolver.solver.constraints.Constraint;
import org.chocosolver.solver.expression.discrete.relational.ReExpression;
@@ -61,7 +63,7 @@ public abstract class PatternProblem extends ChocoProblem<Pattern, PatternProble

    private List<Measure> allMeasures;
    protected Database database;
    private PatternSearchMonitor monitor;
    private ISolutionProvider<Pattern> solutionProvider;

    // CP variables
    protected BoolVar[] items;
@@ -249,14 +251,19 @@ public abstract class PatternProblem extends ChocoProblem<Pattern, PatternProble

    private void plugSearchMonitor() {
        List<String> allMeasuresId = allMeasures.stream().map(Measure::getId).collect(Collectors.toList());
        List<String> paretoMeasuresId = skypatternMeasures.stream().map(Measure::getId).collect(Collectors.toList());
        TransactionGetter transactionGetter = saveTrans ? transactionGetter() : null;
        monitor = new PatternSearchMonitor(database, items, allMeasuresId, paretoMeasuresId, measureVars,
                transactionGetter);
        PatternCreator creator = new PatternCreator(database, items, allMeasuresId, measureVars, transactionGetter);
        if (skypatternMeasures.size() == 0) {
            SolutionRecorderMonitor<Pattern> monitor = new SolutionRecorderMonitor<>(creator);
            solver.plugMonitor(monitor);
        if (paretoMeasuresId.size() > 0) {
            solutionProvider = monitor;
        }
        else {
            IntVar[] obj = skypatternMeasures.stream().map(m -> measureVars.get(m.getId())).toArray(IntVar[]::new);
            model.post(new Constraint("Pareto", new ParetoPatternMaximizer(obj, monitor)));
            SkypatternMonitor monitor = new SkypatternMonitor(obj, creator);
            model.post(new Constraint("Pareto", monitor));
            solver.plugMonitor(monitor);
            solutionProvider = monitor;
        }
    }

@@ -266,7 +273,7 @@ public abstract class PatternProblem extends ChocoProblem<Pattern, PatternProble

    @Override
    public List<Pattern> getSolutions() {
        return monitor.getPatterns();
        return Objects.isNull(solutionProvider) ? null : solutionProvider.getSolutions();
    }

    @Override
+18 −0
Original line number Diff line number Diff line
package io.gitlab.chaver.mining.patterns.search.loop.monitors;

import io.gitlab.chaver.chocotools.objective.IntParetoMaximizer;
import io.gitlab.chaver.chocotools.util.Creator;
import io.gitlab.chaver.mining.patterns.io.Pattern;
import org.chocosolver.solver.variables.IntVar;

public class SkypatternMonitor extends IntParetoMaximizer<Pattern> {

    public SkypatternMonitor(IntVar[] objectives, Creator<Pattern> creator) {
        super(objectives, creator);
    }

    @Override
    protected int[] getObjValues(Pattern sol) {
        return sol.getMeasures();
    }
}
+10 −18
Original line number Diff line number Diff line
package io.gitlab.chaver.mining.patterns.search.loop.monitors;
package io.gitlab.chaver.mining.patterns.util;

import io.gitlab.chaver.chocotools.util.Creator;
import io.gitlab.chaver.mining.patterns.io.Database;
import io.gitlab.chaver.mining.patterns.io.Pattern;
import io.gitlab.chaver.mining.patterns.util.TransactionGetter;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.chocosolver.solver.search.loop.monitors.IMonitorSolution;
import org.chocosolver.solver.variables.BoolVar;
import org.chocosolver.solver.variables.IntVar;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;

@AllArgsConstructor
public class PatternSearchMonitor implements IMonitorSolution {
public class PatternCreator implements Creator<Pattern> {

    protected final @Getter List<Pattern> patterns = new LinkedList<>();
    protected Database database;
    protected BoolVar[] items;
    protected List<String> allMeasuresId;
    protected List<String> paretoMeasuresId;
    protected Map<String, IntVar> measureVars;
    protected TransactionGetter transactionGetter;
    private Database database;
    private BoolVar[] items;
    private List<String> allMeasuresId;
    private Map<String, IntVar> measureVars;
    private TransactionGetter transactionGetter;

    @Override
    public void onSolution() {
    public Pattern create() {
        int[] itemSave = IntStream
                .range(0, items.length)
                .filter(i -> items[i].isInstantiatedTo(1))
@@ -38,9 +33,6 @@ public class PatternSearchMonitor implements IMonitorSolution {
        }
        Pattern p = new Pattern(itemSave, measureSave);
        if (transactionGetter != null) p.setTransactions(transactionGetter.getTransactions());
        patterns.add(p);
        if (paretoMeasuresId.size() > 0) {
            patterns.removeIf(p2 -> p2.isDominatedBy(p, paretoMeasuresId.size()));
        }
        return p;
    }
}