View Javadoc

1   /*******************************************************************************
2   * SAT4J: a SATisfiability library for Java Copyright (C) 2004-2008 Daniel Le
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  package org.sat4j.reader;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.InputStreamReader;
24  import java.io.LineNumberReader;
25  import java.io.PrintWriter;
26  import java.util.HashMap;
27  import java.util.LinkedHashMap;
28  import java.util.Map;
29  import java.util.Scanner;
30  
31  import org.sat4j.core.Vec;
32  import org.sat4j.csp.Clausifiable;
33  import org.sat4j.csp.Constant;
34  import org.sat4j.csp.Domain;
35  import org.sat4j.csp.EnumeratedDomain;
36  import org.sat4j.csp.Evaluable;
37  import org.sat4j.csp.Predicate;
38  import org.sat4j.csp.RangeDomain;
39  import org.sat4j.csp.Var;
40  import org.sat4j.csp.constraints.AllDiff;
41  import org.sat4j.csp.constraints.Nogoods;
42  import org.sat4j.csp.constraints.Relation;
43  import org.sat4j.csp.constraints.WalshSupports;
44  import org.sat4j.specs.ContradictionException;
45  import org.sat4j.specs.IProblem;
46  import org.sat4j.specs.ISolver;
47  import org.sat4j.specs.IVec;
48  
49  /**
50   * This class is a CSP to SAT translator that is able to read a CSP problem
51   * using the First CSP solver competition input format and that translates it
52   * into clausal and cardinality (equality) constraints.
53   * 
54   * That code has not been tested very thoroughly yet and was written very
55   * quickly to meet the competition deadline :=)) There is plenty of room for
56   * improvement.
57   * 
58   * @author leberre
59   * 
60   */
61  public class CSPReader extends Reader implements org.sat4j.csp.xml.ICSPCallback {
62  
63      private final ISolver solver;
64  
65      // private Var[] vars;
66  
67      protected Relation[] relations;
68  
69      private int valueindex;
70  
71      // private int varindex;
72  
73      private int relindex;
74  
75      private int[] currentdomain;
76  
77      private Domain rangedomain;
78  
79      private String currentdomainid;
80  
81      private int currentdomainsize;
82  
83      private final Map<String, Domain> domainmapping = new HashMap<String, Domain>();
84  
85      private final Map<String, Var> varmapping = new LinkedHashMap<String, Var>();
86  
87      private final Map<String, Integer> relmapping = new HashMap<String, Integer>();
88  
89      private final Map<String, Clausifiable> predmapping = new HashMap<String, Clausifiable>();
90  
91      private int nbvarstocreate;
92  
93      private int tupleindex;
94  
95      private Clausifiable currentclausifiable;
96  
97      private Predicate currentpredicate;
98  
99      private final IVec<Evaluable> variables = new Vec<Evaluable>();
100 
101     private final IVec<Var> scope = new Vec<Var>();
102 
103     private int nbvars;
104 
105     private int nbconstraints;
106 
107     private int currentconstraint;
108 
109     public CSPReader(ISolver solver) {
110         this.solver = solver;
111         Clausifiable allDiff = new AllDiff(); 
112         predmapping.put("global:allDifferent",allDiff); // XCSP 2.0 compatibility
113         predmapping.put("global:alldifferent",allDiff);
114     }
115 
116     @Override
117     public final IProblem parseInstance(final java.io.Reader in)
118             throws ParseFormatException, ContradictionException, IOException {
119         return parseInstance(new LineNumberReader(in));
120 
121     }
122 
123     private IProblem parseInstance(LineNumberReader in)
124             throws ParseFormatException {
125         solver.reset();
126         try {
127             readProblem(in);
128             return solver;
129         } catch (NumberFormatException e) {
130             throw new ParseFormatException("integer value expected on line "
131                     + in.getLineNumber(), e);
132         }
133     }
134 
135     @Override
136     public void decode(int[] model, PrintWriter out) {
137         // verifier que les variables sont bien dans le bon ordre !!!!
138         for (Var v : varmapping.values()) {
139             out.print(v.findValue(model));
140             out.print(" ");
141         }
142     }
143 
144     @Override
145     public String decode(int[] model) {
146         StringBuilder stb = new StringBuilder();
147         // verifier que les variables sont bien dans le bon ordre !!!!
148         for (Var v : varmapping.values()) {
149             stb.append(v.findValue(model));
150             stb.append(" ");
151         }
152         return stb.toString();
153     }
154 
155     private void readProblem(LineNumberReader in) {
156         Scanner input = new Scanner(in);
157         // discard problem name
158         beginInstance(input.nextLine());
159 
160         // read number of domain
161         int nbdomain = input.nextInt();
162         beginDomainsSection(nbdomain);
163 
164         for (int i = 0; i < nbdomain; i++) {
165             // read domain number
166             int dnum = input.nextInt();
167             assert dnum == i;
168             // read domain
169             int[] domain = readArrayOfInt(input);
170             beginDomain("" + dnum, domain.length);
171             for (int j = 0; j < domain.length; j++) {
172                 addDomainValue(domain[j]);
173             }
174             endDomain();
175         }
176         endDomainsSection();
177         int nbvar = input.nextInt();
178         beginVariablesSection(nbvar);
179         for (int i = 0; i < nbvar; i++) {
180             // read var number
181             int varnum = input.nextInt();
182             assert varnum == i;
183             // read var domain
184             int vardom = input.nextInt();
185             addVariable("" + varnum, "" + vardom);
186         }
187         endVariablesSection();
188 
189         // relation definition
190         // read number of relations
191         int nbrel = input.nextInt();
192         beginRelationsSection(nbrel);
193         for (int i = 0; i < nbrel; i++) {
194 
195             // read relation number
196             int relnum = input.nextInt();
197             assert relnum == i;
198 
199             boolean forbidden = input.nextInt() == 1 ? false : true;
200             int[] rdomains = readArrayOfInt(input);
201 
202             int nbtuples = input.nextInt();
203 
204             beginRelation("" + relnum, rdomains.length, nbtuples, !forbidden);
205 
206             for (int j = 0; j < nbtuples; j++) {
207                 int[] tuple = readArrayOfInt(input, relations[relnum].arity());
208                 // do something with tuple
209                 addRelationTuple(tuple);
210             }
211 
212             endRelation();
213         }
214         endRelationsSection();
215         int nbconstr = input.nextInt();
216         beginConstraintsSection(nbconstr);
217         // constraint definition
218         for (int i = 0; i < nbconstr; i++) {
219             int[] theVariables = readArrayOfInt(input);
220             beginConstraint("" + i, theVariables.length);
221             int relnum = input.nextInt();
222             // manage constraint
223             constraintReference("" + relnum);
224             for (int v : theVariables) {
225                 addEffectiveParameter("" + v);
226             }
227             endConstraint();
228         }
229         endConstraintsSection();
230         endInstance();
231     }
232 
233     protected void manageAllowedTuples(int relnum, int arity, int nbtuples) {
234         relations[relnum] = new WalshSupports(arity, nbtuples);
235     }
236 
237     // private Var[] intToVar(int[] variables) {
238     // Var[] nvars = new Var[variables.length];
239     // for (int i = 0; i < variables.length; i++)
240     // nvars[i] = vars[variables[i]];
241     // return nvars;
242     // }
243 
244     private int[] readArrayOfInt(Scanner input) {
245         int size = input.nextInt();
246         return readArrayOfInt(input, size);
247     }
248 
249     private int[] readArrayOfInt(Scanner input, int size) {
250         int[] tab = new int[size];
251         for (int i = 0; i < size; i++)
252             tab[i] = input.nextInt();
253         return tab;
254     }
255 
256     public void beginInstance(String arg0) {
257         System.out.println("c reading problem named " + arg0);
258     }
259 
260     public void beginDomainsSection(int nbdomain) {
261         System.out.print("c reading domains");
262     }
263 
264     public void beginDomain(String id, int size) {
265         currentdomainsize = size;
266         currentdomain = null;
267         valueindex = -1;
268         currentdomainid = id;
269         rangedomain = null;
270     }
271 
272     public void addDomainValue(int arg0) {
273         if (currentdomain == null) {
274             currentdomain = new int[currentdomainsize];
275         }
276         if (rangedomain != null) {
277             for (int i = 0; i < rangedomain.size(); i++)
278                 currentdomain[++valueindex] = rangedomain.get(i);
279             rangedomain = null;
280         }
281         currentdomain[++valueindex] = arg0;
282     }
283 
284     public void addDomainValue(int begin, int end) {
285         if (currentdomainsize == end - begin + 1)
286             rangedomain = new RangeDomain(begin, end);
287         else {
288             if (currentdomain == null) {
289                 currentdomain = new int[currentdomainsize];
290             }
291             for (int v = begin; v <= end; v++)
292                 currentdomain[++valueindex] = v;
293         }
294     }
295 
296     public void endDomain() {
297         assert rangedomain != null || valueindex == currentdomain.length - 1;
298         if (rangedomain == null)
299             domainmapping.put(currentdomainid, new EnumeratedDomain(
300                     currentdomain));
301         else
302             domainmapping.put(currentdomainid, rangedomain);
303     }
304 
305     public void endDomainsSection() {
306         System.out.println(" done.");
307     }
308 
309     public void beginVariablesSection(int expectedNumberOfVariables) {
310         System.out.print("c reading variables");
311         nbvarstocreate = 0;
312         this.nbvars = expectedNumberOfVariables;
313     }
314 
315     public void addVariable(String idvar, String iddomain) {
316         Domain vardom = domainmapping.get(iddomain);
317         varmapping.put(idvar, new Var(idvar, vardom, nbvarstocreate));
318         nbvarstocreate += vardom.size();
319         if (isVerbose())
320             System.out.print("\rc reading variables " + varmapping.size() + "/"
321                     + nbvars);
322 
323     }
324 
325     public void endVariablesSection() {
326         if (isVerbose())
327             System.out.println("\rc reading variables (" + nbvars + ") done.");
328         else
329             System.out.println(" done.");
330         solver.newVar(nbvarstocreate);
331         try {
332             for (Evaluable v : varmapping.values()) {
333                 v.toClause(solver);
334             }
335         } catch (ContradictionException ce) {
336             assert false;
337         }
338 
339     }
340 
341     public void beginRelationsSection(int nbrel) {
342         System.out.print("c reading relations");
343         relations = new Relation[nbrel];
344         relindex = -1;
345     }
346 
347     public void beginRelation(String name, int arity, int nbTuples,
348             boolean isSupport) {
349         relmapping.put(name, ++relindex);
350         if (isVerbose())
351             System.out.print("\rc reading relations " + relindex + "/"
352                     + relations.length);
353         if (isSupport) {
354             manageAllowedTuples(relindex, arity, nbTuples);
355         } else {
356             relations[relindex] = new Nogoods(arity, nbTuples);
357         }
358         tupleindex = -1;
359     }
360 
361     public void addRelationTuple(int[] tuple) {
362         relations[relindex].addTuple(++tupleindex, tuple);
363     }
364 
365     public void endRelation() {
366     }
367 
368     public void endRelationsSection() {
369         if (isVerbose())
370             System.out.println("\rc reading relations (" + relations.length
371                     + ") done.");
372         else
373             System.out.println(" done.");
374     }
375 
376     public void beginPredicatesSection(int arg0) {
377         System.out.print("c reading predicates ");
378     }
379 
380     public void beginPredicate(String name) {
381         currentpredicate = new Predicate();
382         predmapping.put(name, currentpredicate);
383         if (isVerbose())
384             System.out.print("\rc reading predicate " + predmapping.size());
385     }
386 
387     public void addFormalParameter(String name, String type) {
388         currentpredicate.addVariable(name);
389 
390     }
391 
392     public void predicateExpression(String expr) {
393         currentpredicate.setExpression(expr);
394     }
395 
396     public void endPredicate() {
397         // TODO Auto-generated method stub
398     }
399 
400     public void endPredicatesSection() {
401         if (isVerbose())
402             System.out.println("\rc reading relations (" + predmapping.size()
403                     + ") done.");
404         else
405             System.out.println(" done.");
406     }
407 
408     public void beginConstraintsSection(int arg0) {
409         System.out.println("c reading constraints");
410         nbconstraints = arg0;
411         currentconstraint = 0;
412     }
413 
414     public void beginConstraint(String name, int arity) {
415         variables.clear();
416         variables.ensure(arity);
417         scope.clear();
418         scope.ensure(arity);
419         if (isVerbose())
420             System.out.print("\rc grounding constraint " + name + "("
421                     + (++currentconstraint * 100 / nbconstraints) + "%)");
422     }
423 
424     public void constraintReference(String ref) {
425         Integer id = relmapping.get(ref);
426         if (id == null) {
427             currentclausifiable = predmapping.get(ref);
428         } else {
429             currentclausifiable = relations[id];
430         }
431         if (currentclausifiable ==null) {
432         	throw new IllegalArgumentException("Reference not supported:  "+ref);
433         }
434     }
435 
436     public void addVariableToConstraint(String arg0) {
437         scope.push(varmapping.get(arg0));
438     }
439 
440     public void addEffectiveParameter(String arg0) {
441         variables.push(varmapping.get(arg0));
442     }
443 
444     public void addEffectiveParameter(int arg0) {
445         variables.push(new Constant(arg0));
446     }
447 
448     public void beginParameterList() {
449         throw new UnsupportedOperationException(
450                 "I do not handle parameter list yet!");
451 
452     }
453 
454     public void addIntegerItem(int arg0) {
455         // TODO Auto-generated method stub
456 
457     }
458 
459     public void addVariableItem(String arg0) {
460         // TODO Auto-generated method stub
461 
462     }
463 
464     public void endParamaterList() {
465         // TODO Auto-generated method stub
466 
467     }
468 
469     public void addConstantParameter(String arg0, int arg1) {
470         throw new UnsupportedOperationException(
471                 "I do not handle constant parameter yet!");
472     }
473 
474     public void constraintExpression(String arg0) {
475         throw new UnsupportedOperationException(
476                 "I do not handle constraint expression yet!");
477     }
478 
479     public void endConstraint() {
480         try {
481             currentclausifiable.toClause(solver, scope, variables);
482         } catch (ContradictionException e) {
483             System.err.println("c INSTANCE TRIVIALLY UNSAT");
484         }
485     }
486 
487     public void endConstraintsSection() {
488         if (isVerbose())
489             System.out.println("\rc reading constraints done.");
490         else
491             System.out.println("c done with constraints.");
492     }
493 
494     public void endInstance() {
495         // TODO Auto-generated method stub
496     }
497 
498     IProblem getProblem() {
499         return solver;
500     }
501     
502 	@Override
503 	public IProblem parseInstance(final InputStream in)
504 			throws ParseFormatException, ContradictionException, IOException {
505 		return parseInstance(new InputStreamReader(in));
506 	}
507 }