/* FeatureIDE - An IDE to support feature-oriented software development * Copyright (C) 2005-2009 FeatureIDE Team, University of Magdeburg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * See http://www.fosd.de/featureide/ for further information. */ package featureide.fm.core.editing; import java.util.LinkedList; import org.prop4j.And; import org.prop4j.Literal; import org.prop4j.Node; import org.prop4j.Not; import org.prop4j.Or; import org.prop4j.SatSolver; import org.sat4j.specs.TimeoutException; import featureide.fm.core.FeatureModel; import featureide.fm.core.configuration.Configuration; import featureide.fm.core.configuration.ConfigurationReader; public class ExampleCalculator { private FeatureModel fm; private Node a; private Node[] bChildren; private LinkedList<Integer> bSatisfiable; private int bIndex; private SatSolver solver; private SatSolver exampleSolver = null; private String lastSolution = null; private long timeout; public ExampleCalculator(FeatureModel fm, long timeout) { this.fm = fm; this.timeout = timeout; } public void setLeft(Node a) { a = a.clone().toCNF(); this.a = a; solver = new SatSolver(a, timeout); } public void setRight(Node b) { b = b.clone().toCNF(); if (b instanceof Or) b = new And(b); bChildren = b.getChildren(); bSatisfiable = new LinkedList<Integer>(); bIndex = -1; } public boolean hasNextChild() { return bIndex + 1 < bChildren.length; } public Node nextChild() { return bChildren[++bIndex]; } public void childIsSatisfiable() { bSatisfiable.add(bIndex); } //TODO might return some examples multiple times public Configuration nextExample() throws TimeoutException { if (exampleSolver == null) { if (bSatisfiable.isEmpty() && !findSatisfiable(true)) return null; Node child = bChildren[bSatisfiable.removeFirst()]; exampleSolver = new SatSolver(new And(a, new Not(child.clone())), 1000); } String solution = exampleSolver.getSolution(); if (solution.equals(lastSolution)) { exampleSolver = null; return nextExample(); } Configuration configuration = new Configuration(fm, false); ConfigurationReader reader = new ConfigurationReader(configuration); reader.readFromString(solution); lastSolution = solution; return configuration; } public boolean findSatisfiable(boolean stopEarly) throws TimeoutException { boolean sat = false; while (hasNextChild()) { Node child = nextChild(); if (!(child instanceof Or)) child = new Or(child); Node[] list = Node.clone(child.getChildren()); for (Node node : list) ((Literal) node).positive ^= true; if (solver.isSatisfiable(list)) { childIsSatisfiable(); if (stopEarly) return true; sat = true; } } return sat; } }