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 pseudo boolean algorithms described in:
20   * A fast pseudo-Boolean constraint solver Chai, D.; Kuehlmann, A.
21   * Computer-Aided Design of Integrated Circuits and Systems, IEEE Transactions on
22   * Volume 24, Issue 3, March 2005 Page(s): 305 - 317
23   * 
24   * and 
25   * Heidi E. Dixon, 2004. Automating Pseudo-Boolean Inference within a DPLL 
26   * Framework. Ph.D. Dissertation, University of Oregon.
27   *******************************************************************************/
28  /*=============================================================================
29   * parser for CSP instances represented in XML format
30   * 
31   * Copyright (c) 2006 Olivier ROUSSEL (olivier.roussel <at> cril.univ-artois.fr)
32   * 
33   * Permission is hereby granted, free of charge, to any person obtaining a copy
34   * of this software and associated documentation files (the "Software"), to deal
35   * in the Software without restriction, including without limitation the rights
36   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37   * copies of the Software, and to permit persons to whom the Software is
38   * furnished to do so, subject to the following conditions:
39   * 
40   * The above copyright notice and this permission notice shall be included in
41   * all copies or substantial portions of the Software.
42   * 
43   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
49   * THE SOFTWARE.
50   *=============================================================================
51   */
52  package org.sat4j.pb.reader;
53  
54  import java.io.IOException;
55  import java.math.BigInteger;
56  import java.util.HashMap;
57  import java.util.Iterator;
58  import java.util.Map;
59  
60  import org.sat4j.core.Vec;
61  import org.sat4j.core.VecInt;
62  import org.sat4j.pb.IPBSolver;
63  import org.sat4j.reader.ParseFormatException;
64  import org.sat4j.specs.ContradictionException;
65  import org.sat4j.specs.IVec;
66  import org.sat4j.specs.IVecInt;
67  
68  /**
69   * Reader complying with the PB07 input format.
70   * 
71   * Non-linear to linear translation adapted from the PB07 readers provided by
72   * Olivier Roussel and Vasco Manquinho (was available in C++, not in Java)
73   * 
74   * http://www.cril.univ-artois.fr/PB07/parser/SimpleParser.java
75   * http://www.cril.univ-artois.fr/PB07/parser/SimpleParser.cc
76   * 
77   * @author parrain
78   * @author daniel
79   * 
80   */
81  public class OPBReader2007 extends OPBReader2006 {
82  
83  	/**
84       * 
85       */
86  	private static final long serialVersionUID = 1L;
87  
88  	/**
89  	 * @param solver
90  	 */
91  	public OPBReader2007(IPBSolver solver) {
92  		super(solver);
93  	}
94  
95  	@Override
96  	protected boolean isGoodFirstCharacter(char c) {
97  		return Character.isLetter(c) || c == '_' || c == '~';
98  	}
99  
100 	@Override
101 	protected void checkId(StringBuffer s) throws ParseFormatException {
102 		// Small check on the coefficient ID to make sure everything is ok
103 		int cpt = 1;
104 		if (s.charAt(0) == '~')
105 			cpt = 2;
106 		int varID = Integer.parseInt(s.substring(cpt));
107 		if (varID > nbVars) {
108 			throw new ParseFormatException(
109 					"Variable identifier larger than #variables in metadata.");
110 		}
111 	}
112 
113 	/**
114 	 * contains the number of new symbols generated to linearize products
115 	 */
116 	private int nbNewSymbols;
117 
118 	@Override
119 	protected void readTerm(StringBuffer coeff, StringBuffer var)
120 			throws IOException, ParseFormatException {
121 		readInteger(coeff);
122 
123 		skipSpaces();
124 
125 		var.setLength(0);
126 		IVec<String> tmpLit = new Vec<String>();
127 		StringBuffer tmpVar = new StringBuffer();
128 		while (readIdentifier(tmpVar)) {
129 			tmpLit = tmpLit.push(tmpVar.toString());
130 			skipSpaces();
131 		}
132 		if (tmpLit.size() == 0)
133 			throw new ParseFormatException("identifier expected");
134 		if (tmpLit.size() == 1) {
135 			// it is a "normal" term
136 			var.append(tmpLit.last());
137 			tmpLit.pop();
138 		} else {
139 			// it is a product term
140 			try {
141 				var.append(linearizeProduct(tmpLit));
142 			} catch (ContradictionException e) {
143 				throw new ParseFormatException(e);
144 			}
145 		}
146 	}
147 
148 	/**
149 	 * callback called when we read a term of a constraint
150 	 * 
151 	 * @param var
152 	 *            the identifier of the variable
153 	 * @param lits
154 	 *            a set of literals in DIMACS format in which var once
155 	 *            translated will be added.
156 	 */
157 	protected void literalInAProduct(String var, IVecInt lits) {
158 		int beginning = ((var.charAt(0) == '~') ? 2 : 1);
159 		int id = Integer.parseInt(var.substring(beginning));
160 		int lid = ((var.charAt(0) == '~') ? -1 : 1) * id;
161 		lits.push(lid);
162 	}
163 
164 	/**
165 	 * callback called when we read a term of a constraint
166 	 * 
167 	 * @param var
168 	 *            the identifier of the variable
169 	 * @param lits
170 	 *            a set of literals in DIMACS format in which var once
171 	 *            translated will be added.
172 	 */
173 	protected void negateLiteralInAProduct(String var, IVecInt lits) {
174 		int beginning = ((var.charAt(0) == '~') ? 2 : 1);
175 		int id = Integer.parseInt(var.substring(beginning));
176 		int lid = ((var.charAt(0) == '~') ? 1 : -1) * id;
177 		lits.push(lid);
178 	}
179 
180 	/**
181 	 * read the first comment line to get the number of variables and the number
182 	 * of constraints in the file calls metaData with the data that was read
183 	 * 
184 	 * @throws IOException
185 	 * @throws ParseException
186 	 */
187 	@Override
188 	protected void readMetaData() throws IOException, ParseFormatException {
189 		char c;
190 		String s;
191 
192 		// get the number of variables and constraints
193 		c = get();
194 		if (c != '*')
195 			throw new ParseFormatException(
196 					"First line of input file should be a comment");
197 		s = readWord();
198 		if (eof() || !"#variable=".equals(s))
199 			throw new ParseFormatException(
200 					"First line should contain #variable= as first keyword");
201 
202 		nbVars = Integer.parseInt(readWord());
203 		nbNewSymbols = nbVars + 1;
204 
205 		s = readWord();
206 		if (eof() || !"#constraint=".equals(s))
207 			throw new ParseFormatException(
208 					"First line should contain #constraint= as second keyword");
209 
210 		nbConstr = Integer.parseInt(readWord());
211 		charAvailable = false;
212 		if (!eol()) {
213 			String rest = in.readLine();
214 
215 			if (rest != null && rest.indexOf("#product=") != -1) {
216 				String[] splitted = rest.trim().split(" ");
217 				if (splitted[0].equals("#product=")) {
218 					Integer.parseInt(splitted[1]);
219 				}
220 
221 				// if (splitted[2].equals("sizeproduct="))
222 				// readWord();
223 
224 			}
225 		}
226 		// callback to transmit the data
227 		metaData(nbVars, nbConstr);
228 	}
229 
230 	@Override
231 	protected int translateVarToId(String var) {
232 		int beginning = ((var.charAt(0) == '~') ? 2 : 1);
233 		int id = Integer.parseInt(var.substring(beginning));
234 		return ((var.charAt(0) == '~') ? -1 : 1) * id;
235 	}
236 
237 	private String linearizeProduct(IVec<String> tmpLit)
238 			throws ContradictionException {
239 		tmpLit.sort(String.CASE_INSENSITIVE_ORDER);
240 		String newVar = getProductVariable(tmpLit);
241 		if (newVar == null) {
242 			// generate a new symbol
243 			newVar = "X" + String.valueOf(nbNewSymbols++);
244 			// linearization proposed by O. Roussel (PB07)
245 			// generate the clause
246 			// product => newSymbol (this is a clause)
247 			// not x1 or not x2 ... or not xn or newSymbol
248 			productStore.put(newVar, tmpLit);
249 			IVecInt newLits = new VecInt();
250 			for (Iterator<String> iterator = tmpLit.iterator(); iterator
251 					.hasNext();)
252 				negateLiteralInAProduct(iterator.next(), newLits);
253 			literalInAProduct(newVar, newLits);
254 			solver.addClause(newLits);
255 			// generate the PB-constraint
256 			// newSymbol => product translated as
257 			// x1+x2+x3...+xn-n*newSymbol>=0
258 			newLits.clear();
259 			IVec<BigInteger> newCoefs = new Vec<BigInteger>();
260 			for (Iterator<String> iterator = tmpLit.iterator(); iterator
261 					.hasNext();) {
262 				literalInAProduct(iterator.next(), newLits);
263 				newCoefs.push(BigInteger.ONE);
264 			}
265 			literalInAProduct(newVar, newLits);
266 			newCoefs.push(new BigInteger(String.valueOf(-tmpLit.size())));
267 			solver.addPseudoBoolean(newLits, newCoefs, true, BigInteger.ZERO);
268 			// nbConstraintsRead += 2;
269 		}
270 		return newVar;
271 	}
272 
273 	private final Map<String, IVec<String>> productStore = new HashMap<String, IVec<String>>();
274 
275 	private String getProductVariable(IVec<String> lits) {
276 		for (Map.Entry<String, IVec<String>> c : productStore.entrySet())
277 			if (c.getValue().equals(lits))
278 				return c.getKey();
279 		return null;
280 	}
281 
282 }