1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.sat4j.reader;
26
27 import java.io.BufferedReader;
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
34 import org.sat4j.core.Vec;
35 import org.sat4j.core.VecInt;
36 import org.sat4j.opt.ObjectiveFunction;
37 import org.sat4j.specs.ContradictionException;
38 import org.sat4j.specs.IProblem;
39 import org.sat4j.specs.ISolver;
40 import org.sat4j.specs.IVec;
41 import org.sat4j.specs.IVecInt;
42
43
44
45
46
47
48
49
50 public class OPBReader2005 extends Reader implements Serializable {
51
52
53
54
55 private static final long serialVersionUID = 1L;
56
57 protected final ISolver solver;
58
59 private final IVecInt lits;
60
61 private final IVec<BigInteger> coeffs;
62
63 private BigInteger d;
64
65 private String operator;
66
67 private final IVecInt objectiveVars = new VecInt();
68
69 private final IVec<BigInteger> objectiveCoeffs = new Vec<BigInteger>();
70
71
72 private boolean hasObjFunc = false;
73
74 protected int nbVars, nbConstr;
75
76 protected int nbConstraintsRead;
77
78
79
80
81
82
83
84
85
86 protected void metaData(int nbvar, int nbconstr) {
87 solver.newVar(nbvar);
88 }
89
90
91
92
93 protected void beginObjective() {
94 }
95
96
97
98
99 protected void endObjective() {
100 assert lits.size() == coeffs.size();
101 assert lits.size() == coeffs.size();
102 for (int i = 0; i < lits.size(); i++) {
103 objectiveVars.push(lits.get(i));
104 objectiveCoeffs.push(coeffs.get(i));
105 }
106 }
107
108
109
110
111 protected void beginConstraint() {
112 lits.clear();
113 coeffs.clear();
114 assert lits.size() == 0;
115 assert coeffs.size() == 0;
116 }
117
118
119
120
121
122
123
124 protected void endConstraint() throws ContradictionException {
125
126 assert !(lits.size() == 0);
127 assert !(coeffs.size() == 0);
128 assert lits.size() == coeffs.size();
129
130 if ("<=".equals(operator) || "=".equals(operator)){
131 solver.addPseudoBoolean(lits, coeffs, false, d);
132 }
133 if (">=".equals(operator) || "=".equals(operator)){
134 solver.addPseudoBoolean(lits, coeffs, true, d);
135 }
136 nbConstraintsRead++;
137 }
138
139
140
141
142
143
144
145
146
147 private void constraintTerm(BigInteger coeff, String var) {
148 coeffs.push(coeff);
149 lits.push(translateVarToId(var));
150 }
151
152 protected int translateVarToId(String var) {
153 int id = Integer.parseInt(var.substring(1));
154 return ((savedChar == '-') ? -1 : 1) * id;
155 }
156
157
158
159
160
161
162
163 protected void constraintRelOp(String relop) {
164 operator = relop;
165 }
166
167
168
169
170
171
172
173
174 protected void constraintRightTerm(BigInteger val) {
175 d = val;
176 }
177
178 transient BufferedReader in;
179
180 char savedChar;
181
182 boolean charAvailable = false;
183
184 boolean eofReached = false;
185
186
187
188
189
190
191 protected char get() throws IOException {
192 int c;
193
194 if (charAvailable) {
195 charAvailable = false;
196 return savedChar;
197 }
198
199 c = in.read();
200 if (c == -1)
201 eofReached = true;
202
203 return (char) c;
204 }
205
206 public IVecInt getVars() {
207 return objectiveVars;
208 }
209
210 public IVec<BigInteger> getCoeffs() {
211 return objectiveCoeffs;
212 }
213
214
215
216
217 private void putback(char c) {
218 savedChar = c;
219 charAvailable = true;
220 }
221
222
223
224
225 protected boolean eof() {
226 return eofReached;
227 }
228
229
230
231
232
233
234 protected void skipSpaces() throws IOException {
235 char c;
236
237 while (Character.isWhitespace(c = get()))
238 ;
239
240 putback(c);
241 }
242
243
244
245
246
247
248
249 public String readWord() throws IOException {
250 StringBuffer s = new StringBuffer();
251 char c;
252
253 skipSpaces();
254
255 while (!Character.isWhitespace(c = get()) && !eof())
256 s.append(c);
257
258 return s.toString();
259 }
260
261
262
263
264
265
266
267
268 public void readInteger(StringBuffer s) throws IOException {
269 char c;
270
271 skipSpaces();
272 s.setLength(0);
273
274 c = get();
275 if (c == '-' || Character.isDigit(c))
276 s.append(c);
277
278
279 while (Character.isDigit(c = get()) && !eof())
280 s.append(c);
281
282 putback(c);
283 }
284
285
286
287
288
289
290
291
292 protected boolean readIdentifier(StringBuffer s) throws IOException,
293 ParseFormatException {
294 char c;
295
296 s.setLength(0);
297
298 skipSpaces();
299
300
301 c = get();
302 if (eof())
303 return false;
304
305 if (!isGoodFirstCharacter(c)) {
306 putback(c);
307 return false;
308 }
309
310 s.append(c);
311
312
313 while (true) {
314 c = get();
315 if (eof())
316 break;
317
318 if (isGoodFollowingCharacter(c))
319 s.append(c);
320 else {
321 putback(c);
322 break;
323 }
324 }
325 checkId(s);
326 return true;
327 }
328
329 protected boolean isGoodFirstCharacter(char c){
330 return Character.isLetter(c) || c == '_';
331 }
332
333 protected boolean isGoodFollowingCharacter(char c){
334 return Character.isLetter(c) || Character.isDigit(c) || c == '_';
335 }
336
337 protected void checkId(StringBuffer s) throws ParseFormatException{
338
339 int varID = Integer.parseInt(s.substring(1));
340 if (varID > nbVars) {
341 throw new ParseFormatException(
342 "Variable identifier larger than #variables in metadata.");
343 }
344 }
345
346
347
348
349
350
351 private String readRelOp() throws IOException {
352 char c;
353
354 skipSpaces();
355
356 c = get();
357 if (eof())
358 return null;
359
360 if (c == '=')
361 return "=";
362
363 if (c == '>' && get() == '=')
364 return ">=";
365
366 return null;
367 }
368
369
370
371
372
373
374
375
376 protected void readMetaData() throws IOException, ParseFormatException {
377 char c;
378 String s;
379
380
381 c = get();
382 if (c != '*')
383 throw new ParseFormatException(
384 "First line of input file should be a comment");
385
386 s = readWord();
387 if (eof() || !"#variable=".equals(s))
388 throw new ParseFormatException(
389 "First line should contain #variable= as first keyword");
390
391 nbVars = Integer.parseInt(readWord());
392
393 s = readWord();
394 if (eof() || !"#constraint=".equals(s))
395 throw new ParseFormatException(
396 "First line should contain #constraint= as second keyword");
397
398 nbConstr = Integer.parseInt(readWord());
399
400
401 in.readLine();
402
403
404 metaData(nbVars, nbConstr);
405 }
406
407
408
409
410
411
412 private void skipComments() throws IOException {
413 char c = ' ';
414
415
416
417 while (!eof() && (c = get()) == '*') {
418 in.readLine();
419 }
420
421 putback(c);
422 }
423
424
425
426
427
428
429
430
431
432
433
434 protected void readTerm(StringBuffer coeff, StringBuffer var)
435 throws IOException, ParseFormatException, ContradictionException {
436 char c;
437
438 readInteger(coeff);
439
440 skipSpaces();
441 c = get();
442 if (c != '*')
443 throw new ParseFormatException(
444 "'*' expected between a coefficient and a variable");
445
446 if (!readIdentifier(var))
447 throw new ParseFormatException("identifier expected");
448 }
449
450
451
452
453
454
455
456
457 private void readObjective() throws IOException, ParseFormatException {
458 char c;
459 StringBuffer var = new StringBuffer();
460 StringBuffer coeff = new StringBuffer();
461
462
463
464 skipSpaces();
465 c = get();
466 if (c != 'm') {
467
468 putback(c);
469 return;
470 }
471
472 hasObjFunc = true;
473 if (get() == 'i' && get() == 'n' && get() == ':') {
474 beginObjective();
475
476 while (!eof()) {
477 try {
478 readTerm(coeff, var);
479 } catch (ContradictionException e) {
480
481 e.printStackTrace();
482 }
483 constraintTerm(new BigInteger(coeff.toString()), var.toString());
484
485 skipSpaces();
486 c = get();
487 if (c == ';')
488 break;
489
490 else if (c == '-' || c == '+' || Character.isDigit(c))
491 putback(c);
492 else
493 throw new ParseFormatException(
494 "unexpected character in objective function");
495 }
496
497 endObjective();
498 } else
499 throw new ParseFormatException(
500 "input format error: 'min:' expected");
501 }
502
503
504
505
506
507
508
509
510 private void readConstraint() throws IOException, ParseFormatException,
511 ContradictionException {
512 StringBuffer var = new StringBuffer();
513 StringBuffer coeff = new StringBuffer();
514 char c;
515
516 beginConstraint();
517
518 while (!eof()) {
519 readTerm(coeff, var);
520 constraintTerm(new BigInteger(coeff.toString()), var.toString());
521
522 skipSpaces();
523 c = get();
524 if (c == '>' || c == '=') {
525
526 putback(c);
527 break;
528 } else if (c == '-' || c == '+' || Character.isDigit(c))
529 putback(c);
530 else {
531 throw new ParseFormatException(
532 "unexpected character in constraint");
533 }
534 }
535
536 if (eof())
537 throw new ParseFormatException(
538 "unexpected EOF before end of constraint");
539
540 String relop;
541 if ((relop = readRelOp()) == null) {
542 throw new ParseFormatException(
543 "unexpected relational operator in constraint");
544
545 }
546 constraintRelOp(relop);
547 readInteger(coeff);
548 constraintRightTerm(new BigInteger(coeff.toString()));
549
550 skipSpaces();
551 c = get();
552 if (eof() || c != ';')
553 throw new ParseFormatException(
554 "semicolon expected at end of constraint");
555
556 endConstraint();
557 }
558
559 public OPBReader2005(ISolver solver) {
560 this.solver = solver;
561 lits = new VecInt();
562 coeffs = new Vec<BigInteger>();
563 }
564
565
566
567
568
569
570
571
572
573 public void parse() throws IOException, ParseFormatException,
574 ContradictionException {
575 readMetaData();
576
577 skipComments();
578
579 readObjective();
580
581
582 nbConstraintsRead = 0;
583 char c;
584 while (!eof()) {
585 skipSpaces();
586 if (eof())
587 break;
588
589 c = get();
590 putback(c);
591 if (c == '*')
592 skipComments();
593
594 if (eof())
595 break;
596
597 readConstraint();
598
599 }
600
601 if (nbConstraintsRead != nbConstr) {
602 throw new ParseFormatException(
603 "Number of constraints read is different from metadata.");
604 }
605 }
606
607 @Override
608 public final IProblem parseInstance(final java.io.Reader in)
609 throws ParseFormatException, ContradictionException {
610 return parseInstance(new LineNumberReader(in));
611 }
612
613 private IProblem parseInstance(LineNumberReader in)
614 throws ParseFormatException, ContradictionException {
615 solver.reset();
616 this.in = in;
617 try {
618 parse();
619 return solver;
620 } catch (IOException e) {
621 throw new ParseFormatException(e);
622 }
623 }
624
625 @Override
626 public String decode(int[] model) {
627 StringBuffer stb = new StringBuffer();
628
629 for (int i = 0; i < model.length; i++) {
630 if (model[i] < 0) {
631 stb.append("-x");
632 stb.append(-model[i]);
633 } else {
634 stb.append("x");
635 stb.append(model[i]);
636 }
637 stb.append(" ");
638 }
639 return stb.toString();
640 }
641
642 @Override
643 public void decode(int[] model, PrintWriter out) {
644 for (int i = 0; i < model.length; i++) {
645 if (model[i] < 0) {
646 out.print("-x");
647 out.print(-model[i]);
648 } else {
649 out.print("x");
650 out.print(model[i]);
651 }
652 out.print(" ");
653 }
654 }
655
656 public ObjectiveFunction getObjectiveFunction() {
657 if (hasObjFunc){
658 return new ObjectiveFunction(getVars(), getCoeffs());
659 }
660 return null;
661 }
662
663 }