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