View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004, 2012 Artois University and CNRS
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   * Contributors:
28   *   CRIL - initial API and implementation
29   *******************************************************************************/
30  
31  package org.sat4j.pb;
32  
33  import static org.junit.Assert.assertEquals;
34  import static org.junit.Assert.assertFalse;
35  import static org.junit.Assert.assertTrue;
36  import static org.sat4j.pb.tools.WeightedObject.newWO;
37  
38  import java.math.BigInteger;
39  import java.util.ArrayList;
40  import java.util.Arrays;
41  import java.util.Collection;
42  import java.util.Iterator;
43  import java.util.List;
44  import java.util.Set;
45  
46  import org.junit.Before;
47  import org.junit.Test;
48  import org.sat4j.pb.tools.DependencyHelper;
49  import org.sat4j.pb.tools.StringNegator;
50  import org.sat4j.pb.tools.WeightedObject;
51  import org.sat4j.specs.ContradictionException;
52  import org.sat4j.specs.IVec;
53  import org.sat4j.specs.TimeoutException;
54  
55  public class TestDependencyHelper {
56  	private static final String profile = "profile";
57  	private static final String junit3 = "junit_3";
58  	private static final String junit4 = "junit_4";
59  
60  	private DependencyHelper<String, String> helper;
61  
62  	@Before
63  	public void setUp() {
64  		this.helper = new DependencyHelper<String, String>(
65  				SolverFactory.newEclipseP2());
66  		// helper = new
67  		// DependencyHelper<String,String>(SolverFactory.newDefault(),10);
68  	}
69  
70  	@Test
71  	public void testBasicRequirements() throws ContradictionException,
72  			TimeoutException {
73  		this.helper.implication("A").implies("B").and("C").and("D").named("I1");
74  		this.helper.implication("B").impliesNot("C").named("I2");
75  		this.helper.setTrue("A", "User selection");
76  		assertFalse(this.helper.hasASolution());
77  		// assertEquals("C",helper.getConflictingElement());
78  		Set<String> cause = this.helper.why();
79  		assertEquals(3, cause.size());
80  		Iterator<String> it = cause.iterator();
81  		assertEquals("I1", it.next());
82  		assertTrue(it.hasNext());
83  		assertEquals("I2", it.next());
84  		assertTrue(it.hasNext());
85  		assertEquals("User selection", it.next());
86  	}
87  
88  	@Test
89  	public void testBasicRequirementsDetailedExplanation()
90  			throws ContradictionException, TimeoutException {
91  		this.helper.implication("A").implies("B").named("I1b");
92  		this.helper.implication("A").implies("C").named("I1c");
93  		this.helper.implication("A").implies("D").named("I1d");
94  		this.helper.implication("B").impliesNot("C").named("I2");
95  		this.helper.setTrue("A", "User selection");
96  		assertFalse(this.helper.hasASolution());
97  		// assertEquals("C",helper.getConflictingElement());
98  		Set<String> cause = this.helper.why();
99  		assertEquals(4, cause.size());
100 		Iterator<String> it = cause.iterator();
101 		assertEquals("I1b", it.next());
102 		assertEquals("I1c", it.next());
103 		assertEquals("I2", it.next());
104 		assertEquals("User selection", it.next());
105 	}
106 
107 	@Test
108 	public void testDisjunctions() throws ContradictionException,
109 			TimeoutException {
110 		this.helper.implication("A").implies("B").and("C").and("D").named("I1");
111 		this.helper.implication("C").implies("C1", "C2", "C3")
112 				.named("C versions");
113 		this.helper.atMost(1, "C1", "C2", "C3").named("Singleton on C");
114 		this.helper.setTrue("A", "User selection");
115 		assertTrue(this.helper.hasASolution());
116 		IVec<String> solution = this.helper.getSolution();
117 		assertTrue(solution.contains("A"));
118 		assertTrue(solution.contains("B"));
119 		assertTrue(solution.contains("C"));
120 		assertTrue(solution.contains("D"));
121 		if (solution.contains("C1")) {
122 			assertFalse(solution.contains("C2"));
123 			assertFalse(solution.contains("C3"));
124 		}
125 		if (solution.contains("C2")) {
126 			assertFalse(solution.contains("C1"));
127 			assertFalse(solution.contains("C3"));
128 		}
129 		if (solution.contains("C3")) {
130 			assertFalse(solution.contains("C1"));
131 			assertFalse(solution.contains("C2"));
132 		}
133 	}
134 
135 	@Test
136 	public void testDisjunctionExplanation() throws ContradictionException,
137 			TimeoutException {
138 		this.helper.implication("A").implies("B").and("C").and("D").named("I1");
139 		this.helper.implication("B").impliesNot("C1").named("I2");
140 		this.helper.implication("D").impliesNot("C2").named("I3");
141 		this.helper.implication("C").implies("C1", "C2").named("C versions");
142 		this.helper.atMost(1, "C1", "C2", "C3").named("Singleton on C");
143 		this.helper.setTrue("A", "User selection");
144 		assertFalse(this.helper.hasASolution());
145 		// assertTrue(helper.getConflictingElement().startsWith("C"));
146 		Set<String> cause = this.helper.why();
147 		assertEquals(5, cause.size());
148 		Iterator<String> it = cause.iterator();
149 		assertEquals("C versions", it.next());
150 		assertEquals("I1", it.next());
151 		assertEquals("I2", it.next());
152 		assertEquals("I3", it.next());
153 		assertEquals("User selection", it.next());
154 	}
155 
156 	@Test
157 	public void testExplanationForASolution() throws ContradictionException,
158 			TimeoutException {
159 		this.helper.implication("A").implies("B").and("C").and("D").named("I1");
160 		this.helper.implication("C").implies("C1", "C2", "C3")
161 				.named("C versions");
162 		this.helper.atMost(1, "C1", "C2", "C3").named("Singleton on C");
163 		this.helper.setTrue("A", "User selection");
164 		assertTrue(this.helper.hasASolution());
165 		IVec<String> solution = this.helper.getSolution();
166 		assertTrue(solution.contains("A"));
167 		assertTrue(solution.contains("B"));
168 		assertTrue(solution.contains("C"));
169 		assertTrue(solution.contains("D"));
170 		Set<String> cause = this.helper.why("D");
171 		assertEquals(2, cause.size());
172 		Iterator<String> it = cause.iterator();
173 		assertEquals("I1", it.next());
174 		assertEquals("User selection", it.next());
175 	}
176 
177 	@Test
178 	public void testObjectiveFunction() throws ContradictionException,
179 			TimeoutException {
180 		this.helper.implication("A").implies("B").and("C").and("D").named("I1");
181 		this.helper.implication("C").implies("C1", "C2", "C3")
182 				.named("C versions");
183 		this.helper.atMost(1, "C1", "C2", "C3").named("Singleton on C");
184 		this.helper.setTrue("A", "User selection");
185 		this.helper.setObjectiveFunction(newWO("C1", 4), newWO("C2", 2),
186 				newWO("C3", 1));
187 		assertTrue(this.helper.hasASolution());
188 		IVec<String> solution = this.helper.getSolution();
189 		assertTrue(solution.contains("A"));
190 		assertTrue(solution.contains("B"));
191 		assertTrue(solution.contains("C"));
192 		assertTrue(solution.contains("C3"));
193 		assertFalse(solution.contains("C2"));
194 		assertFalse(solution.contains("C1"));
195 		assertTrue(solution.contains("D"));
196 	}
197 
198 	@Test
199 	public void testJunitExample() throws ContradictionException,
200 			TimeoutException {
201 		this.helper.implication(profile).implies(junit3)
202 				.named("profile->junit_3");
203 		this.helper.implication(profile).implies(junit4)
204 				.named("profile->junit_4");
205 		this.helper.setObjectiveFunction(WeightedObject.newWO(junit4, 1),
206 				WeightedObject.newWO(junit3, 2));
207 		this.helper.setTrue(profile, "profile must exist");
208 		assertTrue(this.helper.hasASolution());
209 		List<String> expected = new ArrayList<String>(Arrays.asList(profile,
210 				junit3, junit4));
211 		IVec<String> solution = this.helper.getSolution();
212 		for (Iterator<String> i = solution.iterator(); i.hasNext();) {
213 			String variable = i.next();
214 			assertTrue(variable + " was not part of the solution",
215 					expected.remove(variable));
216 		}
217 		assertTrue("solution contained too many variables: " + expected,
218 				expected.isEmpty());
219 	}
220 
221 	@Test
222 	public void testJunitSingletonObjectiveExample()
223 			throws ContradictionException, TimeoutException {
224 		this.helper.implication(profile).implies(junit3, junit4)
225 				.named("profile->junit");
226 		this.helper.atMost(1, junit4, junit3);
227 		this.helper.setObjectiveFunction(WeightedObject.newWO(junit4, 1),
228 				WeightedObject.newWO(junit3, 2));
229 		this.helper.setTrue(profile, "profile must exist");
230 		assertTrue(this.helper.hasASolution());
231 		List<String> expected = new ArrayList<String>(Arrays.asList(profile,
232 				junit4));
233 		IVec<String> solution = this.helper.getSolution();
234 		for (Iterator<String> i = solution.iterator(); i.hasNext();) {
235 			String variable = i.next();
236 			assertTrue(variable + " was not part of the solution",
237 					expected.remove(variable));
238 		}
239 		assertTrue("solution contained too many variables: " + expected,
240 				expected.isEmpty());
241 	}
242 
243 	@Test
244 	public void testEquivalency() throws ContradictionException,
245 			TimeoutException {
246 		this.helper.implication("A").implies("B").named("C1");
247 		this.helper.iff("C2", "B", "C");
248 		this.helper.setTrue("A", "C3");
249 		assertTrue(this.helper.hasASolution());
250 		this.helper.setFalse("C", "C4");
251 		assertFalse(this.helper.hasASolution());
252 	}
253 
254 	@Test
255 	public void testDisjunction() throws ContradictionException,
256 			TimeoutException {
257 		// A or B -> C or D
258 		this.helper.disjunction("A", "B").implies("C", "D").named("C1");
259 		// -> A or B ( equivalent to A or B )
260 		this.helper.implication().implies("A", "B").named("C2");
261 		this.helper.setFalse("C", "C3");
262 		assertTrue(this.helper.hasASolution());
263 		this.helper.setFalse("D", "C4");
264 		assertFalse(this.helper.hasASolution());
265 
266 	}
267 
268 	@Test
269 	public void testCathyExamples() throws ContradictionException,
270 			TimeoutException {
271 		this.helper.setNegator(StringNegator.INSTANCE);
272 		// A <=> B and C and D
273 		this.helper.and("C1", "A", "B", "C", "D");
274 		// not A or B implies E
275 		this.helper.implication("-A", "B").implies("E").named("C2");
276 		this.helper.setFalse("D", "InitState");
277 		this.helper.setTrue("B", "InitState");
278 		this.helper.setFalse("E", "InitState");
279 		this.helper.atMost(1, "A", "B", "C", "D", "E").named("C5");
280 		assertFalse(this.helper.hasASolution());
281 		assertEquals(3, this.helper.why().size());
282 	}
283 
284 	@Test
285 	public void testCardinalityConstraints() throws ContradictionException,
286 			TimeoutException {
287 		this.helper.setNegator(StringNegator.INSTANCE);
288 		// A + B + C <= 2
289 		this.helper.atMost("C1", 2, "A", "B", "C");
290 		this.helper.atLeast("C2", 2, "A", "B", "C");
291 		this.helper.setFalse("C3", "A");
292 		assertTrue(this.helper.hasASolution());
293 		IVec<String> solution = this.helper.getSolution();
294 		assertTrue(solution.contains("B"));
295 		assertTrue(solution.contains("C"));
296 	}
297 
298 	@Test
299 	public void testPseudoConstraints() throws ContradictionException,
300 			TimeoutException {
301 		this.helper.setNegator(StringNegator.INSTANCE);
302 		// 3A + 2B + C <= 5
303 		this.helper.atMost("C1", BigInteger.valueOf(5),
304 				WeightedObject.newWO("A", 3), WeightedObject.newWO("B", 2),
305 				WeightedObject.newWO("C", 1));
306 		this.helper.atLeast("C2", BigInteger.valueOf(7),
307 				WeightedObject.newWO("A", 6), WeightedObject.newWO("B", 4),
308 				WeightedObject.newWO("C", 2));
309 		assertTrue(this.helper.hasASolution());
310 		IVec<String> solution = this.helper.getSolution();
311 		assertTrue(solution.contains("A"));
312 		assertFalse(solution.contains("B") && solution.contains("C"));
313 	}
314 
315 	@Test
316 	public void testPseudoConstraintsNegativeLiterals()
317 			throws ContradictionException, TimeoutException {
318 		this.helper.setNegator(StringNegator.INSTANCE);
319 		// 3A + 2B + C <= 5
320 		this.helper.atMost("C1", BigInteger.valueOf(5),
321 				WeightedObject.newWO("A", 3), WeightedObject.newWO("B", 2),
322 				WeightedObject.newWO("C", 1));
323 		this.helper.atMost("C2", BigInteger.valueOf(1),
324 				WeightedObject.newWO("-A", 3), WeightedObject.newWO("-B", 2),
325 				WeightedObject.newWO("-C", 1));
326 		assertTrue(this.helper.hasASolution());
327 		IVec<String> solution = this.helper.getSolution();
328 		assertTrue(solution.contains("A"));
329 		assertTrue(solution.contains("B"));
330 		assertFalse(solution.contains("C"));
331 	}
332 
333 	@Test
334 	public void testIgnoreContiguousDuplicatedEntry()
335 			throws ContradictionException {
336 		this.helper.setNegator(StringNegator.INSTANCE);
337 		this.helper.clause("C1", "A", "-B", "C");
338 		this.helper.clause("C2", "A", "-B", "C");
339 		this.helper.clause("C3", "A", "-B", "C");
340 		this.helper.clause("C4", "A", "-B", "C");
341 		this.helper.clause("C5", "-A", "-B", "C");
342 		this.helper.clause("C6", "A", "-B", "-C");
343 		this.helper.clause("C7", "A", "B", "C");
344 		assertEquals(4, this.helper.getNumberOfConstraints());
345 	}
346 
347 	@Test
348 	public void testNonDuplicatedEntryNotCatched()
349 			throws ContradictionException {
350 		this.helper.setNegator(StringNegator.INSTANCE);
351 		this.helper.clause("C1", "A", "-B", "C");
352 		this.helper.clause("C2", "A", "B", "C");
353 		this.helper.clause("C3", "A", "-B", "C");
354 		this.helper.clause("C4", "A", "B", "C");
355 		this.helper.clause("C5", "-A", "-B", "C");
356 		this.helper.clause("C6", "A", "-B", "-C");
357 		this.helper.clause("C7", "A", "B", "C");
358 		assertEquals(7, this.helper.getNumberOfConstraints());
359 	}
360 
361 	@Test
362 	public void testLimitofHashFunction() throws ContradictionException {
363 		this.helper.setNegator(StringNegator.INSTANCE);
364 		this.helper.clause("C0", "A", "B", "C", "D");
365 		this.helper.clause("C1", "A", "-B", "C");
366 		this.helper.clause("C2", "D", "-B");
367 		this.helper.clause("C3", "A", "-B", "C");
368 		this.helper.clause("C4", "A", "-B", "C");
369 		this.helper.clause("C5", "A", "-B", "C");
370 		this.helper.clause("C6", "A", "-B", "C");
371 		this.helper.clause("C7", "A", "B", "C");
372 		assertEquals(5, this.helper.getNumberOfConstraints());
373 	}
374 
375 	@Test
376 	public void testVariablesIntroducedInNegativeFormFirst()
377 			throws ContradictionException, TimeoutException {
378 		this.helper.setNegator(StringNegator.INSTANCE);
379 		this.helper.clause("C0", "-A", "-B");
380 		this.helper.clause("C1", "A", "-B");
381 		this.helper.clause("C2", "-A", "B");
382 		this.helper.clause("C3", "A", "B");
383 		assertFalse(this.helper.hasASolution());
384 	}
385 
386 	@Test
387 	public void testVariablesIntroducedInNegativeFormFirstStoredCorrectly()
388 			throws ContradictionException, TimeoutException {
389 		this.helper.setNegator(StringNegator.INSTANCE);
390 		this.helper.clause("C0", "-A", "-B");
391 		this.helper.clause("C1", "A", "-B");
392 		this.helper.clause("C3", "A", "B");
393 		assertTrue(this.helper.hasASolution());
394 		IVec<String> solution = this.helper.getSolution();
395 		assertTrue(solution.contains("A"));
396 		assertFalse(solution.contains("B"));
397 	}
398 
399 	@Test
400 	// testcase for SAT-77
401 	public void testThatWeCanRetrieveTheTruthValueOfNegatedObjects()
402 			throws ContradictionException, TimeoutException {
403 		this.helper.setNegator(StringNegator.INSTANCE);
404 		this.helper.clause("C0", "-A", "-B");
405 		this.helper.clause("C1", "A", "-B");
406 		this.helper.clause("C3", "A", "B");
407 		assertTrue(this.helper.hasASolution());
408 		assertTrue(this.helper.getBooleanValueFor("A"));
409 		assertTrue(this.helper.getBooleanValueFor("-B"));
410 	}
411 
412 	@Test
413 	public void testImpliedObjects() throws ContradictionException,
414 			TimeoutException {
415 		this.helper.setNegator(StringNegator.INSTANCE);
416 		this.helper.clause("C0", "A", "B", "C");
417 		this.helper.clause("C1", "-A", "-B");
418 		this.helper.clause("C2", "-A", "-C");
419 		this.helper.clause("C2", "-B", "-C");
420 		assertTrue(this.helper.hasASolution());
421 		Collection<String> assumptions = new ArrayList<String>();
422 		assumptions.add("A");
423 		Collection<String> satisfied = new ArrayList<String>();
424 		Collection<String> falsified = new ArrayList<String>();
425 		this.helper.impliedBy(assumptions, satisfied, falsified);
426 		assertEquals(">>>" + satisfied, 1, satisfied.size());
427 		assertTrue(satisfied.contains("A"));
428 		assertEquals(2, falsified.size());
429 		assertTrue(falsified.contains("B"));
430 		assertTrue(falsified.contains("C"));
431 	}
432 
433 }