All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.solver.QuickXPlain Maven / Gradle / Ivy

There is a newer version: 4.10.17
Show newest version
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2023, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 *
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.solver;

import org.chocosolver.solver.constraints.Constraint;

import java.util.*;

/**
 * QuickXPlain is intended to find a minimum conflict set of constraints that's causing
 * a conflict in the solver execution [1].
 * This implementation is an improved version from that proposed in the discussion from issue #509.
 * 

* 1. Ulrich Junker. 2004. QUICKXPLAIN: preferred explanations and relaxations for over-constrained * problems. In Proceedings of the 19th national conference on Artifical intelligence * AAAI Press, 167–172. * * @author Joao Pedro Schmitt * @since 03/12/2020 */ public class QuickXPlain { private final Model model; public QuickXPlain(Model model) { this.model = model; } /** * Given a set of conflicting constraints that block the solver from find a solution * for a problem, returns the minimum conflicting set to be relaxed in such a way to put * the solver back in a feasible search space. * * @param conflictingSet * @return minimumConflictingSet */ public List findMinimumConflictingSet(List conflictingSet) { List allConstraints = getAllConstraints(); List background = getBackground(allConstraints, conflictingSet); List minimumConflictSet; if (conflictingSet.isEmpty() || isConsistent(allConstraints)) minimumConflictSet = Collections.emptyList(); else { minimumConflictSet = qx(background, background, conflictingSet); } model.getSolver().reset(); return minimumConflictSet; } /** * Execute quickXPlain algorithm to find the minimum conflicting set. * * @param background * @param conflict * @param constraints * @return */ private List qx(List background, List conflict, List constraints) { if (!conflict.isEmpty() && !isConsistent(background)) { return Collections.emptyList(); } if (constraints.size() == 1) { return constraints; } int k = constraints.size() / 2; List c1 = new ArrayList<>(constraints.subList(0, k)); List c2 = new ArrayList<>(constraints.subList(k, constraints.size())); List prevB = new ArrayList<>(background); List d2 = qx(constraintsUnion(background, c1), c1, c2); List conflictSet = new ArrayList<>(d2); List d1 = qx(constraintsUnion(prevB, d2), d2, c1); Set constraintSetHash = new HashSet<>(conflictSet); for (int i = 0; i < d1.size(); i++) { if (!constraintSetHash.contains(d1.get(i))) { conflictSet.add(d1.get(i)); } } return conflictSet; } private boolean isConsistent(List background) { model.getSolver().reset(); Set constraintsHash = new HashSet<>(background); Constraint[] constraints = model.getCstrs(); for (int i = 0; i < constraints.length; i++) { constraints[i].setEnabled(constraintsHash.contains(constraints[i])); } return model.getSolver().solve(); } public List constraintsUnion(List c1, List c2) { c1.addAll(c2); return c1; } /** * Background is the set of constraints that can not be relaxed. * * @param allConstraints * @param conflictingSet * @return background */ private List getBackground(List allConstraints, List conflictingSet) { List knowledgeBase = new ArrayList<>(allConstraints.size() - conflictingSet.size()); Set conflictSetHash = new HashSet<>(conflictingSet); for (Constraint cstr : allConstraints) { if (!conflictSetHash.contains(cstr)) { knowledgeBase.add(cstr); } } return knowledgeBase; } private List getAllConstraints() { List allConstraints = new ArrayList<>(model.getNbCstrs()); Constraint[] cstrs = model.getCstrs(); Collections.addAll(allConstraints, cstrs); return allConstraints; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy