View Javadoc

1   /*******************************************************************************
2    * SAT4J: a SATisfiability library for Java Copyright (C) 2004, 2012 Artois University and CNRS
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   * Based on the original MiniSat specification from:
20   *
21   * An extensible SAT solver. Niklas Een and Niklas Sorensson. Proceedings of the
22   * Sixth International Conference on Theory and Applications of Satisfiability
23   * Testing, LNCS 2919, pp 502-518, 2003.
24   *
25   * See www.minisat.se for the original solver in C++.
26   *
27   * Contributors:
28   *   CRIL - initial API and implementation
29   *******************************************************************************/
30  
31  package org.sat4j.tools.encoding;
32  
33  import org.sat4j.core.ConstrGroup;
34  import org.sat4j.core.VecInt;
35  import org.sat4j.specs.ContradictionException;
36  import org.sat4j.specs.IConstr;
37  import org.sat4j.specs.ISolver;
38  import org.sat4j.specs.IVecInt;
39  
40  /**
41   * Binary encoding for the "at most one" and "at most k" cases.
42   * 
43   * For the case "at most one", we can use the binary encoding (also called
44   * birwise encoding) first described in A. M. Frisch, T. J. Peugniez, A. J.
45   * Dogget and P. Nightingale, "Solving Non-Boolean Satisfiability Problems With
46   * Stochastic Local Search: A Comparison of Encodings" in Journal of Automated
47   * Reasoning, vol. 35, n 1-3, 2005.
48   * 
49   * The approach is generalized for the "at most k" case in A. M. Frisch and P.
50   * A. Giannaros, "SAT Encodings of the At-Most-k Constraint", in International
51   * Workshop on Modelling and Reformulating Constraint Satisfaction Problems,
52   * 2010
53   * 
54   * @author sroussel
55   * @since 2.3.1
56   */
57  public class Binary extends EncodingStrategyAdapter {
58  
59      /**
60       * p being the smaller integer greater than log_2(n), this encoding adds p
61       * variables and n*p clauses.
62       * 
63       */
64      @Override
65      public IConstr addAtMostOne(ISolver solver, IVecInt literals)
66              throws ContradictionException {
67          ConstrGroup group = new ConstrGroup(false);
68  
69          final int n = literals.size();
70          final int p = (int) Math.ceil(Math.log(n) / Math.log(2));
71          final int k = (int) Math.pow(2, p) - n;
72  
73          int y[] = new int[p];
74          for (int i = 0; i < p; i++) {
75              y[i] = solver.nextFreeVarId(true);
76          }
77  
78          IVecInt clause = new VecInt();
79          String binary = "";
80  
81          for (int i = 0; i < k; i++) {
82              binary = Integer.toBinaryString(i);
83              while (binary.length() != p - 1) {
84                  binary = "0" + binary;
85              }
86  
87              for (int j = 0; j < p - 1; j++) {
88                  clause.push(-literals.get(i));
89                  if (binary.charAt(j) == '0') {
90                      clause.push(-y[j]);
91                  } else {
92                      clause.push(y[j]);
93                  }
94                  group.add(solver.addClause(clause));
95                  clause.clear();
96  
97              }
98          }
99  
100         for (int i = k; i < n; i++) {
101             binary = Integer.toBinaryString(2 * k + i - k);
102             while (binary.length() != p) {
103                 binary = "0" + binary;
104             }
105             for (int j = 0; j < p; j++) {
106                 clause.push(-literals.get(i));
107                 if (binary.charAt(j) == '0') {
108                     clause.push(-y[j]);
109                 } else {
110                     clause.push(y[j]);
111                 }
112                 group.add(solver.addClause(clause));
113                 clause.clear();
114             }
115 
116         }
117 
118         return group;
119     }
120 
121     @Override
122     public IConstr addAtMost(ISolver solver, IVecInt literals, int k)
123             throws ContradictionException {
124 
125         final int n = literals.size();
126         final int p = (int) Math.ceil(Math.log(n) / Math.log(2));
127 
128         ConstrGroup group = new ConstrGroup(false);
129 
130         int[][] b = new int[k][p];
131 
132         for (int i = 0; i < k; i++) {
133             for (int j = 0; j < p; j++) {
134                 b[i][j] = solver.nextFreeVarId(true);
135             }
136         }
137 
138         int[][] t = new int[k][n];
139 
140         for (int i = 0; i < k; i++) {
141             for (int j = 0; j < n; j++) {
142                 t[i][j] = solver.nextFreeVarId(true);
143             }
144         }
145 
146         int max, min;
147         IVecInt clause1 = new VecInt();
148         IVecInt clause2 = new VecInt();
149         String binary = "";
150         for (int i = 0; i < n; i++) {
151             max = Math.max(1, k - n + i + 1);
152             min = Math.min(i + 1, k);
153             clause1.push(-literals.get(i));
154 
155             binary = Integer.toBinaryString(i);
156             while (binary.length() != p) {
157                 binary = "0" + binary;
158             }
159 
160             for (int g = max - 1; g < min; g++) {
161                 clause1.push(t[g][i]);
162                 for (int j = 0; j < p; j++) {
163                     clause2.push(-t[g][i]);
164                     if (binary.charAt(j) == '0') {
165                         clause2.push(-b[g][j]);
166                     } else {
167                         clause2.push(b[g][j]);
168                     }
169                     group.add(solver.addClause(clause2));
170                     clause2.clear();
171                 }
172             }
173             group.add(solver.addClause(clause1));
174             clause1.clear();
175         }
176 
177         return group;
178     }
179 
180     @Override
181     public IConstr addAtLeast(ISolver solver, IVecInt literals, int k)
182             throws ContradictionException {
183 
184         IVecInt newLits = new VecInt();
185         for (int i = 0; i < literals.size(); i++) {
186             newLits.push(-literals.get(i));
187         }
188 
189         return addAtMost(solver, newLits, literals.size() - k);
190     }
191 
192     @Override
193     public IConstr addExactlyOne(ISolver solver, IVecInt literals)
194             throws ContradictionException {
195         ConstrGroup group = new ConstrGroup();
196 
197         group.add(addAtLeastOne(solver, literals));
198         group.add(addAtMostOne(solver, literals));
199 
200         return group;
201     }
202 
203     @Override
204     public IConstr addExactly(ISolver solver, IVecInt literals, int degree)
205             throws ContradictionException {
206         ConstrGroup group = new ConstrGroup();
207 
208         group.add(addAtLeast(solver, literals, degree));
209         group.add(addAtMost(solver, literals, degree));
210 
211         return group;
212     }
213 }