1 /*
2  * Copyright (c) 2016 Helmut Neemann
3  * Use of this source code is governed by the GPL v3 license
4  * that can be found in the LICENSE file.
5  */
6 package de.neemann.digital.analyse.quinemc;
7 
8 
9 import de.neemann.digital.analyse.expression.Constant;
10 import de.neemann.digital.analyse.expression.Expression;
11 import de.neemann.digital.analyse.expression.Variable;
12 
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.List;
16 import java.util.TreeSet;
17 
18 import static de.neemann.digital.analyse.expression.Not.not;
19 import static de.neemann.digital.analyse.expression.Operation.and;
20 
21 /**
22  * Represents a row in a QMC table
23  */
24 public final class TableRow implements Comparable<TableRow> {
25 
26     private final TreeSet<Integer> source;
27     private boolean used = false;
28     private long optimizedFlags;
29     private long state;
30     private int cols;
31 
32     /**
33      * Copies the given table row
34      *
35      * @param tr the row to copy
36      */
TableRow(TableRow tr)37     public TableRow(TableRow tr) {
38         this(tr.size());
39         state = tr.state;
40         optimizedFlags = tr.optimizedFlags;
41     }
42 
43     /**
44      * Creates a new table row
45      *
46      * @param cols number of columns
47      */
TableRow(int cols)48     public TableRow(int cols) {
49         this.cols = cols;
50         source = new TreeSet<>();
51     }
52 
53     /**
54      * Creates a new row
55      *
56      * @param cols     the number of columns
57      * @param bitValue the value representing the bits in the row
58      * @param index    the index of the original source row
59      * @param dontCare true if don't care
60      */
TableRow(int cols, int bitValue, int index, boolean dontCare)61     public TableRow(int cols, int bitValue, int index, boolean dontCare) {
62         this(cols, bitValue);
63         if (!dontCare)
64             source.add(index);
65     }
66 
67     /**
68      * Creates a new row.
69      * Used only for exact cover tests!
70      *
71      * @param cols     the number of columns
72      * @param bitValue the value representing the bits in the row
73      */
TableRow(int cols, int bitValue)74     public TableRow(int cols, int bitValue) {
75         this(cols);
76         state = Integer.reverse(bitValue) >>> (32 - cols);
77     }
78 
79 
80     /**
81      * Sets the given index to optimized
82      *
83      * @param index the columns index
84      */
setToOptimized(int index)85     public void setToOptimized(int index) {
86         state &= ~(1L << index);
87         optimizedFlags |= 1L << index;
88     }
89 
90     /**
91      * Returns the optimized flags.
92      * All Variables which are deleted/optimized in this row are marked by a one bit at their position.
93      *
94      * @return the flags
95      */
getOptimizedFlags()96     public long getOptimizedFlags() {
97         return optimizedFlags;
98     }
99 
100     @Override
toString()101     public String toString() {
102         StringBuilder sb = new StringBuilder();
103         for (int c = 0; c < cols; c++) {
104             long mask = 1L << c;
105 
106             if ((optimizedFlags & mask) != 0)
107                 sb.append('-');
108             else if ((state & mask) != 0)
109                 sb.append('1');
110             else
111                 sb.append('0');
112         }
113 
114         for (Integer i : source)
115             sb.append(",").append(i);
116         return sb.toString();
117     }
118 
119     @Override
equals(Object o)120     public boolean equals(Object o) {
121         if (this == o) return true;
122         if (o == null || getClass() != o.getClass()) return false;
123 
124         TableRow tableRow = (TableRow) o;
125 
126         return optimizedFlags == tableRow.optimizedFlags && state == tableRow.state;
127     }
128 
129     @Override
hashCode()130     public int hashCode() {
131         int result = (int) (optimizedFlags ^ (optimizedFlags >>> 32));
132         result = 31 * result + (int) (state ^ (state >>> 32));
133         result = 31 * result + cols;
134         return result;
135     }
136 
137     /**
138      * Set the used flag
139      */
setUsed()140     public void setUsed() {
141         this.used = true;
142     }
143 
144     /**
145      * @return the used flag
146      */
isUsed()147     public boolean isUsed() {
148         return used;
149     }
150 
151     @Override
compareTo(TableRow tableRow)152     public int compareTo(TableRow tableRow) {
153         int e = Long.compare(optimizedFlags, tableRow.optimizedFlags);
154         if (e == 0)
155             return Long.compare(state, tableRow.state);
156         return e;
157     }
158 
159     /**
160      * @return the number of columns
161      */
size()162     public int size() {
163         return cols;
164     }
165 
166     /**
167      * @return the source line numbers
168      */
getSource()169     public Collection<Integer> getSource() {
170         return source;
171     }
172 
173     /**
174      * Adds some sources to this line
175      *
176      * @param s the sources to add
177      */
addSource(Collection<Integer> s)178     public void addSource(Collection<Integer> s) {
179         source.addAll(s);
180     }
181 
182     /**
183      * Adds some sources to this line
184      *
185      * @param s the sources to add
186      * @return this for chained calls
187      */
addSource(Integer... s)188     public TableRow addSource(Integer... s) {
189         addSource(Arrays.asList(s));
190         return this;
191     }
192 
193     /**
194      * Returns an expression build with the given variables
195      *
196      * @param vars the variables to use
197      * @return the expression
198      */
getExpression(List<Variable> vars)199     public Expression getExpression(List<Variable> vars) {
200         Expression e = null;
201         for (int i = 0; i < size(); i++) {
202             long mask = 1L << i;
203             if ((optimizedFlags & mask) == 0) {
204                 Expression term;
205                 if ((state & mask) == 0)
206                     term = not(vars.get(i));
207                 else
208                     term = vars.get(i);
209 
210                 if (e == null)
211                     e = term;
212                 else
213                     e = and(e, term);
214             }
215         }
216         if (e == null)
217             return Constant.ONE;
218         else
219             return e;
220     }
221 
222     /**
223      * Check if rows differ in only one therm
224      *
225      * @param r2 the other row
226      * @return the matching literal or -1
227      */
checkCompatible(TableRow r2)228     public int checkCompatible(TableRow r2) {
229         if (optimizedFlags != r2.optimizedFlags)
230             return -1;
231 
232         long v = state ^ r2.state;
233         if (Long.bitCount(v) != 1)
234             return -1;
235 
236         return Long.numberOfTrailingZeros(v);
237     }
238 }
239