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