View Javadoc

1   /*
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2006 Daniel Le Berre
3    * 
4    * Based on the original minisat specification from:
5    * 
6    * An extensible SAT solver. Niklas E?n and Niklas S?rensson. Proceedings of the
7    * Sixth International Conference on Theory and Applications of Satisfiability
8    * Testing, LNCS 2919, pp 502-518, 2003.
9    * 
10   * This library is free software; you can redistribute it and/or modify it under
11   * the terms of the GNU Lesser General Public License as published by the Free
12   * Software Foundation; either version 2.1 of the License, or (at your option)
13   * any later version.
14   * 
15   * This library is distributed in the hope that it will be useful, but WITHOUT
16   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18   * details.
19   * 
20   * You should have received a copy of the GNU Lesser General Public License
21   * along with this library; if not, write to the Free Software Foundation, Inc.,
22   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23   * 
24   */
25  
26  package org.sat4j.reader;
27  
28  import java.io.IOException;
29  import java.io.LineNumberReader;
30  import java.io.PrintWriter;
31  import java.io.Serializable;
32  import java.math.BigInteger;
33  import java.util.HashMap;
34  import java.util.Map;
35  import java.util.Scanner;
36  
37  import org.sat4j.core.Vec;
38  import org.sat4j.core.VecInt;
39  import org.sat4j.specs.ContradictionException;
40  import org.sat4j.specs.IProblem;
41  import org.sat4j.specs.ISolver;
42  import org.sat4j.specs.IVec;
43  import org.sat4j.specs.IVecInt;
44  
45  /**
46   * This class is a quick hack to read opb formatted files. The reader skip
47   * commented lines (beginning with COMMENT_SYMBOL) and expect constraints of the
48   * form: [name :] [[+|-]COEF] [*] [+|-]LIT >=|<=|= DEGREE where COEF and DEGREE
49   * are plain integer and LIT is an identifier.
50   * 
51   * @author leberre
52   */
53  public class GoodOPBReader extends Reader implements Serializable {
54  
55      /**
56       * Comment for <code>serialVersionUID</code>
57       */
58      private static final long serialVersionUID = 1L;
59  
60      private static final String COMMENT_SYMBOL = "*";
61  
62      private final ISolver solver;
63  
64      private final Map<String, Integer> map = new HashMap<String, Integer>();
65  
66      private final IVec<String> decode = new Vec<String>();
67  
68      /**
69       * 
70       */
71      public GoodOPBReader(ISolver solver) {
72          this.solver = solver;
73      }
74  
75      @Override
76      public final IProblem parseInstance(final java.io.Reader in)
77              throws ParseFormatException, ContradictionException, IOException {
78          return parseInstance(new LineNumberReader(in));
79      }
80  
81      private IProblem parseInstance(LineNumberReader in)
82              throws ContradictionException, IOException {
83          solver.reset();
84          String line;
85          while ((line = in.readLine()) != null) {
86              // cannot trim is line is null
87              line = line.trim();
88              if (line.endsWith(";")) {
89                  line = line.substring(0, line.length() - 1);
90              }
91              parseLine(line);
92          }
93          return solver;
94      }
95  
96      void parseLine(String line) throws ContradictionException {
97          // Skip commented line
98          if (line.startsWith(COMMENT_SYMBOL))
99              return;
100         if (line.startsWith("p")) // ignore p cnf with pbchaff format
101             return;
102         if (line.startsWith("min:") || line.startsWith("min :"))
103             return; // we will use that case later
104         if (line.startsWith("max:") || line.startsWith("max :"))
105             return; // we will use that case later
106 
107         // skip name of constraints:
108         int index = line.indexOf(":");
109         if (index != -1) {
110             line = line.substring(index + 1);
111         }
112 
113         IVecInt lits = new VecInt();
114         IVec<BigInteger> coeffs = new Vec<BigInteger>();
115         Scanner stk = new Scanner(line)
116                 .useDelimiter("\\s*\\*\\s*|\\s*\\+\\s*|\\s+");
117         while (stk.hasNext()) {
118             String token = stk.next();
119             if (">=".equals(token) || "<=".equals(token) || "=".equals(token)) {
120                 assert stk.hasNext();
121                 String tok = stk.next();
122                 // we need to remove + from the integer
123                 if (tok.startsWith("+")) {
124                     tok = tok.substring(1);
125                 }
126                 BigInteger d = new BigInteger(tok);
127 
128                 try {
129                     if (">=".equals(token) || "=".equals(token)) {
130                         solver.addPseudoBoolean(lits, coeffs, true, d);
131                     }
132                     if ("<=".equals(token) || "=".equals(token)) {
133                         solver.addPseudoBoolean(lits, coeffs, false, d);
134                     }
135                 } catch (ContradictionException ce) {
136                     System.out.println("c inconsistent constraint: " + line);
137                     System.out.println("c lits: " + lits);
138                     System.out.println("c coeffs: " + coeffs);
139                     throw ce;
140                 }
141             } else {
142                 // on est toujours en train de lire la partie gauche de la
143                 // contrainte
144                 if ("+".equals(token)) {
145                     assert stk.hasNext();
146                     token = stk.next();
147                 } else if ("-".equals(token)) {
148                     assert stk.hasNext();
149                     token = token + stk.next();
150                 }
151                 BigInteger coef;
152                 // should contain a coef and a literal
153                 try {
154                     // we need to remove + from the integer
155                     if (token.startsWith("+")) {
156                         token = token.substring(1);
157                     }
158                     coef = new BigInteger(token);
159                     assert stk.hasNext();
160                     token = stk.next();
161                 } catch (NumberFormatException nfe) {
162                     // its only an identifier
163                     coef = BigInteger.ONE;
164                 }
165                 if ("-".equals(token) || "~".equals(token)) {
166                     assert stk.hasNext();
167                     token = token + stk.next();
168                 }
169                 boolean negative = false;
170                 if (token.startsWith("+")) {
171                     token = token.substring(1);
172                 } else if (token.startsWith("-")) {
173                     token = token.substring(1);
174                     assert coef.equals(BigInteger.ONE);
175                     coef = BigInteger.ONE.negate();
176                 } else if (token.startsWith("~")) {
177                     token = token.substring(1);
178                     negative = true;
179                 }
180                 Integer id = map.get(token);
181                 if (id == null) {
182                     map.put(token, id = solver.newVar());
183                     decode.push(token);
184                     assert decode.size() == id.intValue();
185                 }
186                 coeffs.push(coef);
187                 int lid = (negative ? -1 : 1) * id.intValue();
188                 lits.push(lid);
189                 assert coeffs.size() == lits.size();
190             }
191         }
192     }
193 
194     @Override
195     public String decode(int[] model) {
196         StringBuffer stb = new StringBuffer();
197         for (int i = 0; i < model.length; i++) {
198             if (model[i] < 0) {
199                 stb.append("-");
200                 stb.append(decode.get(-model[i] - 1));
201             } else {
202                 stb.append(decode.get(model[i] - 1));
203             }
204             stb.append(" ");
205         }
206         return stb.toString();
207     }
208 
209     @Override
210     public void decode(int[] model, PrintWriter out) {
211         for (int i = 0; i < model.length; i++) {
212             if (model[i] < 0) {
213                 out.print("-");
214                 out.print(decode.get(-model[i] - 1));
215             } else {
216                 out.print(decode.get(model[i] - 1));
217             }
218             out.print(" ");
219         }
220     }
221 }