View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2008 Daniel Le Berre
3    *
4    * All rights reserved. This program and the accompanying materials
5    * are made available under the terms of the Eclipse Public License v1.0
6    * which accompanies this distribution, and is available at
7    * http://www.eclipse.org/legal/epl-v10.html
8    *
9    * Alternatively, the contents of this file may be used under the terms of
10   * either the GNU Lesser General Public License Version 2.1 or later (the
11   * "LGPL"), in which case the provisions of the LGPL are applicable instead
12   * of those above. If you wish to allow use of your version of this file only
13   * under the terms of the LGPL, and not to allow others to use your version of
14   * this file under the terms of the EPL, indicate your decision by deleting
15   * the provisions above and replace them with the notice and other provisions
16   * required by the LGPL. If you do not delete the provisions above, a recipient
17   * may use your version of this file under the terms of the EPL or the LGPL.
18   * 
19   * Based on the original MiniSat specification from:
20   * 
21   * An extensible SAT solver. Niklas Een and Niklas Sorensson. Proceedings of the
22   * Sixth International Conference on Theory and Applications of Satisfiability
23   * Testing, LNCS 2919, pp 502-518, 2003.
24   *
25   * See www.minisat.se for the original solver in C++.
26   * 
27   *******************************************************************************/
28  
29  package org.sat4j.tools.encoding;
30  
31  import org.sat4j.core.ConstrGroup;
32  import org.sat4j.core.VecInt;
33  import org.sat4j.specs.ContradictionException;
34  import org.sat4j.specs.IConstr;
35  import org.sat4j.specs.ISolver;
36  import org.sat4j.specs.IVecInt;
37  
38  /**
39   * 
40   * The case "at most one" is introduced in W. Klieber and G. Kwon
41   * "Efficient CNF encoding for selecting 1 from N objects" in Fourth Workshop on
42   * Constraints in Formal Verification, 2007.
43   * 
44   * The generalization to the "at most k" case is described in A. M. Frisch and P
45   * . A. Giannaros, "SAT Encodings of the At-Most-k Constraint", in International
46   * Workshop on Modelling and Reformulating Constraint Satisfaction Problems,
47   * 2010
48   * 
49   * @author sroussel
50   * @since 2.3.1
51   */
52  public class Commander extends EncodingStrategyAdapter {
53  
54  	/**
55  	 * In this encoding, variables are partitioned in groups. Kwon and Klieber
56  	 * claim that the fewest clauses are produced when the size of the groups is
57  	 * 3, thus leading to 3.5 clauses and introducing n/2 variables.
58  	 */
59  	@Override
60  	public IConstr addAtMostOne(ISolver solver, IVecInt literals)
61  			throws ContradictionException {
62  
63  		return addAtMostOne(solver, literals, 3);
64  	}
65  
66  	private IConstr addAtMostOne(ISolver solver, IVecInt literals, int groupSize)
67  			throws ContradictionException {
68  
69  		ConstrGroup constrGroup = new ConstrGroup(false);
70  
71  		IVecInt clause = new VecInt();
72  		IVecInt clause1 = new VecInt();
73  
74  		final int n = literals.size();
75  
76  		int nbGroup = (int) Math.ceil((double) literals.size()
77  				/ (double) groupSize);
78  
79  		if (nbGroup == 1) {
80  			for (int i = 0; i < literals.size() - 1; i++) {
81  				for (int j = i + 1; j < literals.size(); j++) {
82  					clause.push(-literals.get(i));
83  					clause.push(-literals.get(j));
84  					constrGroup.add(solver.addClause(clause));
85  					clause.clear();
86  				}
87  			}
88  			return constrGroup;
89  		}
90  
91  		int[] c = new int[nbGroup];
92  
93  		for (int i = 0; i < nbGroup; i++) {
94  			c[i] = solver.nextFreeVarId(true);
95  		}
96  
97  		int nbVarLastGroup = n - (nbGroup - 1) * groupSize;
98  
99  		// Encoding <=1 for each group of groupLitterals
100 		for (int i = 0; i < nbGroup; i++) {
101 			int size = 0;
102 			if (i == (nbGroup - 1)) {
103 				size = nbVarLastGroup;
104 			} else {
105 				size = groupSize;
106 			}
107 			// Encoding <=1 for each group of groupLitterals
108 			for (int j = 0; j < size - 1; j++) {
109 				for (int k = j + 1; k < size; k++) {
110 					clause.push(-literals.get(i * groupSize + j));
111 					clause.push(-literals.get(i * groupSize + k));
112 					constrGroup.add(solver.addClause(clause));
113 					clause.clear();
114 				}
115 			}
116 
117 			// If a commander variable is true then some variable in its
118 			// corresponding group must be true (clause1)
119 			// If a commander variable is false then no variable in its group
120 			// can be true (clause)
121 			clause1.push(-c[i]);
122 			for (int j = 0; j < size; j++) {
123 				clause1.push(literals.get(i * groupSize + j));
124 				clause.push(c[i]);
125 				clause.push(-literals.get(i * groupSize + j));
126 				constrGroup.add(solver.addClause(clause));
127 				clause.clear();
128 			}
129 			constrGroup.add(solver.addClause(clause1));
130 			clause1.clear();
131 		}
132 
133 		// encode <=1 on commander variables
134 
135 		constrGroup.add(addAtMostOne(solver, new VecInt(c), groupSize));
136 		return constrGroup;
137 	}
138 
139 	@Override
140 	public IConstr addAtMost(ISolver solver, IVecInt literals, int degree)
141 			throws ContradictionException {
142 		return super.addAtMost(solver, literals, degree);
143 		// return addAtMost(solver, literals, degree, degree * 2);
144 	}
145 
146 	private IConstr addAtMost(ISolver solver, IVecInt literals, int k,
147 			int groupSize) throws ContradictionException {
148 		ConstrGroup constrGroup = new ConstrGroup(false);
149 
150 		IVecInt clause = new VecInt();
151 
152 		final int n = literals.size();
153 
154 		int nbGroup = (int) Math.ceil((double) n / (double) groupSize);
155 
156 		if (nbGroup == 1) {
157 			for (IVecInt vec : literals.subset(k + 1)) {
158 				for (int i = 0; i < vec.size(); i++) {
159 					clause.push(-vec.get(i));
160 				}
161 				constrGroup.add(solver.addClause(clause));
162 				clause.clear();
163 			}
164 			return constrGroup;
165 		}
166 
167 		int[][] c = new int[nbGroup][k];
168 		VecInt vecC = new VecInt();
169 
170 		for (int i = 0; i < nbGroup - 1; i++) {
171 			for (int j = 0; j < k; j++) {
172 				c[i][j] = solver.nextFreeVarId(true);
173 				vecC.push(c[i][j]);
174 			}
175 		}
176 
177 		int nbVarLastGroup = n - (nbGroup - 1) * groupSize;
178 		int nbCForLastGroup;
179 		// nbCForLastGroup = Math.min(k, nbVarLastGroup);
180 		nbCForLastGroup = k;
181 
182 		for (int j = 0; j < nbCForLastGroup; j++) {
183 			c[nbGroup - 1][j] = solver.nextFreeVarId(true);
184 			vecC.push(c[nbGroup - 1][j]);
185 		}
186 
187 		VecInt[] groupTab = new VecInt[nbGroup];
188 
189 		// Every literal x is in a group Gi
190 		// For every group Gi, we construct the group every {Gi \cup {c[i][j], j
191 		// =0,...k-1}}
192 		for (int i = 0; i < nbGroup - 1; i++) {
193 			groupTab[i] = new VecInt();
194 
195 			int size = 0;
196 			if (i == (nbGroup - 1)) {
197 				size = nbVarLastGroup;
198 			} else {
199 				size = groupSize;
200 			}
201 
202 			for (int j = 0; j < size; j++) {
203 				groupTab[i].push(literals.get(i * groupSize + j));
204 			}
205 			for (int j = 0; j < k; j++) {
206 				groupTab[i].push(-c[i][j]);
207 			}
208 		}
209 
210 		int size = nbVarLastGroup;
211 		groupTab[nbGroup - 1] = new VecInt();
212 		for (int j = 0; j < size; j++) {
213 			groupTab[nbGroup - 1].push(literals.get((nbGroup - 1) * groupSize
214 					+ j));
215 		}
216 		for (int j = 0; j < nbCForLastGroup; j++) {
217 			groupTab[nbGroup - 1].push(-c[nbGroup - 1][j]);
218 		}
219 
220 		Binomial bin = new Binomial();
221 
222 		// Encode <=k for every Gi \cup {c[i][j], j=0,...k-1}} with Binomial
223 		// encoding
224 		for (int i = 0; i < nbGroup; i++) {
225 			constrGroup.add(bin.addAtMost(solver, groupTab[i], k));
226 			System.out.println(constrGroup.getConstr(i).size());
227 		}
228 
229 		// Encode >=k for every Gi \cup {c[i][j], j=0,...k-1}} with Binomial
230 		// encoding
231 		for (int i = 0; i < nbGroup; i++) {
232 			constrGroup.add(bin.addAtLeast(solver, groupTab[i], k));
233 			System.out.println(constrGroup.getConstr(i + nbGroup).size());
234 		}
235 
236 		for (int i = 0; i < nbGroup; i++) {
237 			for (int j = 0; j < k - 1; j++) {
238 				clause.push(-c[i][j]);
239 				clause.push(c[i][j + 1]);
240 				constrGroup.add(solver.addClause(clause));
241 				clause.clear();
242 			}
243 		}
244 
245 		constrGroup.add(addAtMost(solver, vecC, k));
246 
247 		return constrGroup;
248 	}
249 }