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