View Javadoc

1   /**
2    * 
3    */
4   package org.sat4j.reader;
5   
6   import java.io.IOException;
7   import java.math.BigInteger;
8   import java.util.HashMap;
9   import java.util.Map;
10  
11  import org.sat4j.core.Vec;
12  import org.sat4j.core.VecInt;
13  import org.sat4j.specs.ContradictionException;
14  import org.sat4j.specs.ISolver;
15  import org.sat4j.specs.IVec;
16  import org.sat4j.specs.IVecInt;
17  
18  /**
19   * @author parrain
20   * 
21   */
22  public class OPBReader2007 extends OPBReader2006 {
23  
24      /**
25       * 
26       */
27      private static final long serialVersionUID = 1L;
28  
29      private int nbProducts;
30  
31      // MetaData: #products and productSize in file.
32  
33      /**
34       * @param solver
35       */
36      public OPBReader2007(ISolver solver) {
37          super(solver);
38          // TODO Auto-generated constructor stub
39      }
40  
41      @Override
42      protected boolean isGoodFirstCharacter(char c) {
43          return Character.isLetter(c) || c == '_' || c == '~';
44      }
45  
46      @Override
47      protected void checkId(StringBuffer s) throws ParseFormatException {
48          // Small check on the coefficient ID to make sure everything is ok
49          int cpt = 1;
50          if (s.charAt(0) == '~')
51              cpt = 2;
52          int varID = Integer.parseInt(s.substring(cpt));
53          if (varID > nbVars) {
54              throw new ParseFormatException(
55                      "Variable identifier larger than #variables in metadata.");
56          }
57      }
58  
59      /**
60       * contains the number of new symbols generated to linearize products
61       */
62      private int nbNewSymbols;
63  
64      @Override
65      protected void readTerm(StringBuffer coeff, StringBuffer var)
66              throws IOException, ParseFormatException, ContradictionException {
67          readInteger(coeff);
68  
69          skipSpaces();
70  
71          var.setLength(0);
72          IVec<String> tmpLit = new Vec<String>();
73          StringBuffer tmpVar = new StringBuffer();
74          while (readIdentifier(tmpVar)) {
75              tmpLit = tmpLit.push(tmpVar.toString());
76              skipSpaces();
77          }
78          if (tmpLit.size() == 0)
79              throw new ParseFormatException("identifier expected");
80          if (tmpLit.size() == 1) {
81              // it is a "normal" term
82              var.append(tmpLit.last());
83              tmpLit.pop();
84          } else {
85              // it is a product term
86              var.append(linearizeProduct(tmpLit));
87          }
88      }
89  
90      /**
91       * callback called when we read a term of a constraint
92       * 
93       * @param var
94       *                the identifier of the variable
95       * @param lits
96       *                a set of literals in DIMACS format in which var once
97       *                translated will be added.
98       */
99      protected void literalInAProduct(String var, IVecInt lits) {
100         int beginning = ((var.charAt(0) == '~') ? 2 : 1);
101         int id = Integer.parseInt(var.substring(beginning));
102         int lid = ((var.charAt(0) == '~') ? -1 : 1) * id;
103         lits.push(lid);
104     }
105 
106     /**
107      * callback called when we read a term of a constraint
108      * 
109      * @param var
110      *                the identifier of the variable
111      * @param lits
112      *                a set of literals in DIMACS format in which var once
113      *                translated will be added.
114      */
115     protected void negateLiteralInAProduct(String var, IVecInt lits) {
116         int beginning = ((var.charAt(0) == '~') ? 2 : 1);
117         int id = Integer.parseInt(var.substring(beginning));
118         int lid = ((var.charAt(0) == '~') ? 1 : -1) * id;
119         lits.push(lid);
120     }
121 
122     /**
123      * read the first comment line to get the number of variables and the number
124      * of constraints in the file calls metaData with the data that was read
125      * 
126      * @throws IOException
127      * @throws ParseException
128      */
129     @Override
130     protected void readMetaData() throws IOException, ParseFormatException {
131         char c;
132         String s;
133 
134         // get the number of variables and constraints
135         c = get();
136         if (c != '*')
137             throw new ParseFormatException(
138                     "First line of input file should be a comment");
139 
140         s = readWord();
141         if (eof() || !"#variable=".equals(s))
142             throw new ParseFormatException(
143                     "First line should contain #variable= as first keyword");
144 
145         nbVars = Integer.parseInt(readWord());
146         nbNewSymbols = nbVars + 1;
147 
148         s = readWord();
149         if (eof() || !"#constraint=".equals(s))
150             throw new ParseFormatException(
151                     "First line should contain #constraint= as second keyword");
152 
153         nbConstr = Integer.parseInt(readWord());
154 
155         s = readWord();
156         // if (eof() || !"#product=".equals(s))
157         // throw new ParseFormatException(
158         // "First line should contain #product= as third keyword");
159         if (s.equals("#product=")) {
160             nbProducts = Integer.parseInt(readWord());
161             nbVars += nbProducts;
162             nbConstr += 2 * nbProducts;
163         }
164 
165         s = readWord();
166         // if (eof() || !"sizeproduct=".equals(s))
167         // throw new ParseFormatException(
168         // "First line should contain sizeproduct= as fourth keyword");
169 
170         if (s.equals("sizeproduct="))
171             readWord();
172 
173         // skip the rest of the line
174         in.readLine();
175 
176         // callback to transmit the data
177         metaData(nbVars, nbConstr);
178     }
179 
180     @Override
181     protected int translateVarToId(String var) {
182         int beginning = ((var.charAt(0) == '~') ? 2 : 1);
183         int id = Integer.parseInt(var.substring(beginning));
184         return ((var.charAt(0) == '~') ? -1 : 1) * id;
185     }
186 
187     private String linearizeProduct(IVec<String> tmpLit)
188             throws ContradictionException {
189         tmpLit.sort(String.CASE_INSENSITIVE_ORDER);
190         String newVar = getProductVariable(tmpLit);
191         if (newVar == null) {
192             // generate a new symbol
193             newVar = "X" + String.valueOf(nbNewSymbols++);
194             // linearization proposed by O. Roussel (PB07)
195             // generate the clause
196             // product => newSymbol (this is a clause)
197             // not x1 or not x2 ... or not xn or newSymbol
198             productStore.put(newVar, tmpLit);
199             IVecInt newLits = new VecInt();
200             for (String lit : tmpLit)
201                 negateLiteralInAProduct(lit, newLits);
202             literalInAProduct(newVar, newLits);
203             solver.addClause(newLits);
204             // generate the PB-constraint
205             // newSymbol => product translated as
206             // x1+x2+x3...+xn-n*newSymbol>=0
207             newLits.clear();
208             IVec<BigInteger> newCoefs = new Vec<BigInteger>();
209             for (String lit : tmpLit) {
210                 literalInAProduct(lit, newLits);
211                 newCoefs.push(BigInteger.ONE);
212             }
213             literalInAProduct(newVar, newLits);
214             newCoefs.push(new BigInteger(String.valueOf(-tmpLit.size())));
215             solver.addPseudoBoolean(newLits, newCoefs, true, BigInteger.ZERO);
216             nbConstraintsRead += 2;
217         }
218         return newVar;
219     }
220 
221     private Map<String, IVec<String>> productStore = new HashMap<String, IVec<String>>();
222 
223     private String getProductVariable(IVec<String> lits) {
224         for (Map.Entry<String, IVec<String>> c : productStore.entrySet())
225             if (c.getValue().equals(lits))
226                 return c.getKey();
227         return null;
228     }
229 
230 }