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  package org.sat4j.reader;
29  
30  import java.io.BufferedInputStream;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.io.PrintWriter;
34  import java.io.Serializable;
35  
36  import org.sat4j.core.VecInt;
37  import org.sat4j.specs.ContradictionException;
38  import org.sat4j.specs.IProblem;
39  import org.sat4j.specs.ISolver;
40  import org.sat4j.specs.IVecInt;
41  
42  /**
43   * Dimacs Reader written by Frederic Laihem. It is much faster than DimacsReader
44   * because it does not split the input file into strings but reads and interpret
45   * the input char by char. Hence, it is a bit more difficult to read and to
46   * modify than DimacsReader.
47   * 
48   * This reader is used during the SAT Competitions.
49   * 
50   * @author laihem
51   * @author leberre
52   */
53  public class LecteurDimacs extends Reader implements Serializable {
54  
55  	private static final long serialVersionUID = 1L;
56  
57  	/* taille du buffer */
58  	private final static int TAILLE_BUF = 16384;
59  
60  	private final ISolver s;
61  
62  	private transient BufferedInputStream in;
63  
64  	/* nombre de literaux dans le fichier */
65  	private int nbVars = -1;
66  
67  	private int nbClauses = -1;
68  
69  	private static final char EOF = (char) -1;
70  
71  	/*
72  	 * nomFichier repr?sente le nom du fichier ? lire
73  	 */
74  	public LecteurDimacs(ISolver s) {
75  		this.s = s;
76  	}
77  
78  	@Override
79  	public final IProblem parseInstance(final InputStream input)
80  			throws ParseFormatException, ContradictionException, IOException {
81  
82  		this.in = new BufferedInputStream(input, LecteurDimacs.TAILLE_BUF);
83  		s.reset();
84  		passerCommentaire();
85  		if (nbVars < 0)
86  			throw new ParseFormatException(
87  					"DIMACS error: wrong max number of variables");
88  		s.newVar(nbVars);
89  		s.setExpectedNumberOfClauses(nbClauses);
90  		char car = passerEspaces();
91  		if (nbClauses > 0) {
92  			if (car == EOF)
93  				throw new ParseFormatException(
94  						"DIMACS error: the clauses are missing");
95  			ajouterClauses(car);
96  		}
97  		input.close();
98  		return s;
99  	}
100 
101 	@Override
102 	public IProblem parseInstance(java.io.Reader input) throws IOException,
103 			ContradictionException {
104 		throw new UnsupportedOperationException();
105 	}
106 
107 	/** on passe les commentaires et on lit le nombre de literaux */
108 	private char passerCommentaire() throws IOException {
109 		char car;
110 		for (;;) {
111 			car = passerEspaces();
112 			if (car == 'p') {
113 				car = lectureNombreLiteraux();
114 			}
115 			if (car != 'c' && car != 'p')
116 				break; /* fin des commentaires */
117 			car = nextLine(); /* on passe la ligne de commentaire */
118 			if (car == EOF)
119 				break;
120 		}
121 		return car;
122 	}
123 
124 	/** lit le nombre repr?sentant le nombre de literaux */
125 	private char lectureNombreLiteraux() throws IOException {
126 		char car = nextChiffre(); /* on lit le prchain chiffre */
127 		if (car != EOF) {
128 			nbVars = car - '0';
129 			for (;;) { /* on lit le chiffre repr?sentant le nombre de literaux */
130 				car = (char) in.read();
131 				if (car < '0' || car > '9')
132 					break;
133 				nbVars = 10 * nbVars + (car - '0');
134 			}
135 			car = nextChiffre();
136 			nbClauses = car - '0';
137 			for (;;) { /* on lit le chiffre repr?sentant le nombre de literaux */
138 				car = (char) in.read();
139 				if (car < '0' || car > '9')
140 					break;
141 				nbClauses = 10 * nbClauses + (car - '0');
142 			}
143 			if (car != '\n' && car != EOF)
144 				nextLine(); /* on lit la fin de la ligne */
145 		}
146 		return car;
147 	}
148 
149 	/**
150 	 * lit les clauses et les ajoute dans le vecteur donn? en param?tre
151 	 * 
152 	 * @throws ParseFormatException
153 	 */
154 	private void ajouterClauses(char car) throws IOException,
155 			ContradictionException, ParseFormatException {
156 		final IVecInt lit = new VecInt();
157 		int val = 0;
158 		boolean neg = false;
159 		for (;;) {
160 			/* on lit le signe du literal */
161 			if (car == '-') {
162 				neg = true;
163 				car = (char) in.read();
164 			} else if (car == '+')
165 				car = (char) in.read();
166 			else /* on le 1er chiffre du literal */
167 			if (car >= '0' && car <= '9') {
168 				val = car - '0';
169 				car = (char) in.read();
170 			} else
171 				throw new ParseFormatException("Unknown character " + car);
172 			/* on lit la suite du literal */
173 			while (car >= '0' && car <= '9') {
174 				val = (val * 10) + car - '0';
175 				car = (char) in.read();
176 			}
177 			if (val == 0) { // on a lu toute la clause
178 				s.addClause(lit);
179 				lit.clear();
180 			} else {
181 				/* on ajoute le literal au vecteur */
182 				// s.newVar(val-1);
183 				lit.push(neg ? -val : val);
184 				neg = false;
185 				val = 0; /* on reinitialise les variables */
186 			}
187 			if (car != EOF)
188 				car = passerEspaces();
189 			if (car == EOF) {
190 				if (!lit.isEmpty()) {
191 					s.addClause(lit);
192 				}
193 				break; /* on a lu tout le fichier */
194 			}
195 		}
196 	}
197 
198 	/** passe tout les caract?res d'espacement (espace ou \n) */
199 	private char passerEspaces() throws IOException {
200 		char car;
201 
202 		do {
203 			car = (char) in.read();
204 		} while (car == ' ' || car == '\n');
205 
206 		return car;
207 	}
208 
209 	/** passe tout les caract?res jusqu? rencontrer une fin de la ligne */
210 	private char nextLine() throws IOException {
211 		char car;
212 		do {
213 			car = (char) in.read();
214 		} while ((car != '\n') && (car != EOF));
215 		return car;
216 	}
217 
218 	/** passe tout les caract?re jusqu'? rencontrer un chiffre */
219 	private char nextChiffre() throws IOException {
220 		char car;
221 		do {
222 			car = (char) in.read();
223 		} while ((car < '0') || (car > '9') && (car != EOF));
224 		return car;
225 	}
226 
227 	@Override
228 	public String decode(int[] model) {
229 		StringBuffer stb = new StringBuffer();
230 		for (int i = 0; i < model.length; i++) {
231 			stb.append(model[i]);
232 			stb.append(" ");
233 		}
234 		stb.append("0");
235 		return stb.toString();
236 	}
237 
238 	@Override
239 	public void decode(int[] model, PrintWriter out) {
240 		for (int i = 0; i < model.length; i++) {
241 			out.print(model[i]);
242 			out.print(" ");
243 		}
244 		out.print("0");
245 	}
246 }