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 	/** on passe les commentaires et on lit le nombre de literaux */
102 	private char passerCommentaire() throws IOException {
103 		char car;
104 		for (;;) {
105 			car = passerEspaces();
106 			if (car == 'p') {
107 				car = lectureNombreLiteraux();
108 			}
109 			if (car != 'c' && car != 'p')
110 				break; /* fin des commentaires */
111 			car = nextLine(); /* on passe la ligne de commentaire */
112 			if (car == EOF)
113 				break;
114 		}
115 		return car;
116 	}
117 
118 	/** lit le nombre repr?sentant le nombre de literaux */
119 	private char lectureNombreLiteraux() throws IOException {
120 		char car = nextChiffre(); /* on lit le prchain chiffre */
121 		if (car != EOF) {
122 			nbVars = car - '0';
123 			for (;;) { /* on lit le chiffre repr?sentant le nombre de literaux */
124 				car = (char) in.read();
125 				if (car < '0' || car > '9')
126 					break;
127 				nbVars = 10 * nbVars + (car - '0');
128 			}
129 			car = nextChiffre();
130 			nbClauses = car - '0';
131 			for (;;) { /* on lit le chiffre repr?sentant le nombre de literaux */
132 				car = (char) in.read();
133 				if (car < '0' || car > '9')
134 					break;
135 				nbClauses = 10 * nbClauses + (car - '0');
136 			}
137 			if (car != '\n' && car != EOF)
138 				nextLine(); /* on lit la fin de la ligne */
139 		}
140 		return car;
141 	}
142 
143 	/**
144 	 * lit les clauses et les ajoute dans le vecteur donn? en param?tre
145 	 * 
146 	 * @throws ParseFormatException
147 	 */
148 	private void ajouterClauses(char car) throws IOException,
149 			ContradictionException, ParseFormatException {
150 		final IVecInt lit = new VecInt();
151 		int val = 0;
152 		boolean neg = false;
153 		for (;;) {
154 			/* on lit le signe du literal */
155 			if (car == '-') {
156 				neg = true;
157 				car = (char) in.read();
158 			} else if (car == '+')
159 				car = (char) in.read();
160 			else /* on le 1er chiffre du literal */
161 			if (car >= '0' && car <= '9') {
162 				val = car - '0';
163 				car = (char) in.read();
164 			} else
165 				throw new ParseFormatException("Unknown character " + car);
166 			/* on lit la suite du literal */
167 			while (car >= '0' && car <= '9') {
168 				val = (val * 10) + car - '0';
169 				car = (char) in.read();
170 			}
171 			if (val == 0) { // on a lu toute la clause
172 				s.addClause(lit);
173 				lit.clear();
174 			} else {
175 				/* on ajoute le literal au vecteur */
176 				// s.newVar(val-1);
177 				lit.push(neg ? -val : val);
178 				neg = false;
179 				val = 0; /* on reinitialise les variables */
180 			}
181 			if (car != EOF)
182 				car = passerEspaces();
183 			if (car == EOF) {
184 				if (!lit.isEmpty()) {
185 					s.addClause(lit);
186 				}
187 				break; /* on a lu tout le fichier */
188 			}
189 		}
190 	}
191 
192 	/** passe tout les caract?res d'espacement (espace ou \n) */
193 	private char passerEspaces() throws IOException {
194 		char car;
195 
196 		do {
197 			car = (char) in.read();
198 		} while (car == ' ' || car == '\n');
199 
200 		return car;
201 	}
202 
203 	/** passe tout les caract?res jusqu? rencontrer une fin de la ligne */
204 	private char nextLine() throws IOException {
205 		char car;
206 		do {
207 			car = (char) in.read();
208 		} while ((car != '\n') && (car != EOF));
209 		return car;
210 	}
211 
212 	/** passe tout les caract?re jusqu'? rencontrer un chiffre */
213 	private char nextChiffre() throws IOException {
214 		char car;
215 		do {
216 			car = (char) in.read();
217 		} while ((car < '0') || (car > '9') && (car != EOF));
218 		return car;
219 	}
220 
221 	@Override
222 	public String decode(int[] model) {
223 		StringBuffer stb = new StringBuffer();
224 		for (int i = 0; i < model.length; i++) {
225 			stb.append(model[i]);
226 			stb.append(" ");
227 		}
228 		stb.append("0");
229 		return stb.toString();
230 	}
231 
232 	@Override
233 	public void decode(int[] model, PrintWriter out) {
234 		for (int i = 0; i < model.length; i++) {
235 			out.print(model[i]);
236 			out.print(" ");
237 		}
238 		out.print("0");
239 	}
240 }