/** Adds a new variable. * * @param variable a variable. * @return this equation. * @throws IllegalStateException if you try to add twice the same variable. */ public Modulo2Equation add(final int variable) { assert ! bitVector.getBoolean(variable); bitVector.set(variable); isEmpty = false; return this; }
@Override public String toString() { final StringBuilder b = new StringBuilder(); boolean someNonZero = false; for(int i = 0; i < bitVector.length(); i++) { if (bitVector.getBoolean(i)) { if (someNonZero) b.append(" + "); someNonZero = true; b.append("x_").append(i); } } if (! someNonZero) b.append('0'); return b.append(" = ").append(c).toString(); }
/** Checks whether the given integer is in this filter. * * <P>Note that this method may return true on an integer that has * not been added to the filter. This will happen with probability 2<sup>-<var>d</var></sup>, * where <var>d</var> is the number of hash functions specified at creation time, if * the number of the elements in the filter is less than <var>n</var>, the number * of expected elements specified at creation time. * * @param x an integer. * @return true if the integer is in the filter (or if an integer with the * same hash sequence is in the filter). */ public boolean contains( final int x ) { int i = d; while( i-- != 0 ) if ( ! bits.getBoolean( hash( x, i ) ) ) return false; return true; }
/** Checks whether the given integer is in this filter. * * <P>Note that this method may return true on an integer that has * not been added to the filter. This will happen with probability 2<sup>-<var>d</var></sup>, * where <var>d</var> is the number of hash functions specified at creation time, if * the number of the elements in the filter is less than <var>n</var>, the number * of expected elements specified at creation time. * * @param x an integer. * @return true if the integer is in the filter (or if an integer with the * same hash sequence is in the filter). */ public boolean contains( final int x ) { int i = d; while( i-- != 0 ) if ( ! bits.getBoolean( hash( x, i ) ) ) return false; return true; }
vertex2Edge[v2][p[v2]++] = j; vertex2Edge[v3][p[v3]++] = j; c[j++] = codedValues.getBoolean(i) ? 1 : 0; final int x = stack[--top]; final int e = edge[x]; solution[x] = codedValues.getBoolean(e) ? 1 : 0; if (x != edge2Vertex3[e]) solution[x] ^= solution[edge2Vertex3[e]]; assert (codedValues.getBoolean(e) ? 1 : 0) == (solution[edge2Vertex0[e]] ^ solution[edge2Vertex1[e]] ^ solution[edge2Vertex2[e]] ^ solution[edge2Vertex3[e]]) : edge2String(e) + ": " + (codedValues.getBoolean(e) ? 1 : 0) + " != " + (solution[edge2Vertex0[e]] ^ solution[edge2Vertex1[e]] ^ solution[edge2Vertex2[e]] ^ solution[edge2Vertex2[e]]);
/** Solves the system using lazy Gaussian elimination. * * <p><strong>Warning</strong>: this method is very inefficient, as it * scans linearly the equations, builds from scratch the {@code var2Eq} * parameter of {@link #lazyGaussianElimination(Modulo2System, int[][], long[], int[], long[])}, * and finally calls it. It should be used mainly to write unit tests. * * @param solution an array where the solution will be written. * @return true if the system is solvable. */ public boolean lazyGaussianElimination(final long[] solution) { final int[][] var2Eq = new int[numVars][]; final int[] d = new int[numVars]; for(final Modulo2Equation equation: equations) for(int v = (int)equation.bitVector.length(); v-- != 0;) if (equation.bitVector.getBoolean(v)) d[v]++; for(int v = numVars; v-- != 0;) var2Eq[v] = new int[d[v]]; Arrays.fill(d, 0); final long[] c = new long[equations.size()]; for(int e = 0; e < equations.size(); e++) { c[e] = equations.get(e).c; final LongArrayBitVector bitVector = equations.get(e).bitVector; for(int v = (int)bitVector.length(); v-- != 0;) if (bitVector.getBoolean(v)) var2Eq[v][d[v]++] = e; } return lazyGaussianElimination(this, var2Eq, c, Util.identity(numVars), solution); }
vertex2Edge[v1][p[v1]++] = j; vertex2Edge[v2][p[v2]++] = j; c[j++] = codedValues.getBoolean(i) ? 1 : 0; final int x = stack[--top]; final int e = edge[x]; solution[x] = codedValues.getBoolean(e) ? 1 : 0; if (x != edge2Vertex0[e]) solution[x] ^= solution[edge2Vertex0[e]]; if (x != edge2Vertex1[e]) solution[x] ^= solution[edge2Vertex1[e]]; if (x != edge2Vertex2[e]) solution[x] ^= solution[edge2Vertex2[e]]; final int sol = codedValues.getBoolean(e) ? 1 : 0; assert sol == (solution[edge2Vertex0[e]] ^ solution[edge2Vertex1[e]] ^ solution[edge2Vertex2[e]]) : edge2String(e) + ": " + codedValues.getBoolean(e) + " != " + (solution[edge2Vertex0[e]] ^ solution[edge2Vertex1[e]] ^ solution[edge2Vertex2[e]]);
@Override public boolean removeBoolean(final long index) { if (CHECKS) ensureRestrictedIndex(index); final boolean oldValue = getBoolean(index); final long[] bits = this.bits; final int word = word(index); final int bit = bit(index); bits[word] = (bits[word] & - (1L << bit) << 1) >>> 1 | bits[word] & (1L << bit) - 1; final int numWords = numWords(length--); for(int i = word + 1; i < numWords; i++) { if ((bits[i] & 1) != 0) bits[i - 1] |= LAST_BIT_MASK; bits[i] >>>= 1; } return oldValue; }
/** Returns an array containing the variables in increasing order. * * <p>Mainly for debugging purposes. * * @return an array containing the variables in increasing order. */ public int[] variables() { final IntArrayList variables = new IntArrayList(); for(int i = 0; i < bitVector.length(); i++) if (bitVector.getBoolean(i)) variables.add(i); return variables.toIntArray(); }
public boolean removeBoolean( final long index ) { if ( CHECKS ) ensureRestrictedIndex( index ); final boolean oldValue = getBoolean( index ); final long[] bits = this.bits; final int word = word( index ); final int bit = bit( index ); bits[ word ] = ( bits[ word ] & - ( 1L << bit ) << 1 ) >>> 1 | bits[ word ] & ( 1L << bit ) - 1; final int numWords = numWords( length-- ); for( int i = word + 1; i < numWords; i++ ) { if ( ( bits[ i ] & 1 ) != 0 ) bits[ i - 1 ] |= LAST_BIT_MASK; bits[ i ] >>>= 1; } return oldValue; }
public boolean removeBoolean( final long index ) { if ( CHECKS ) ensureRestrictedIndex( index ); final boolean oldValue = getBoolean( index ); final long[] bits = this.bits; final int word = word( index ); final int bit = bit( index ); bits[ word ] = ( bits[ word ] & - ( 1L << bit ) << 1 ) >>> 1 | bits[ word ] & ( 1L << bit ) - 1; final int numWords = numWords( length-- ); for( int i = word + 1; i < numWords; i++ ) { if ( ( bits[ i ] & 1 ) != 0 ) bits[ i - 1 ] |= LAST_BIT_MASK; bits[ i ] >>>= 1; } return oldValue; }
@Override public long getLong(long index) { if (marker == null) return small.getLong(index); if (marker.getBoolean(index)) return large.getLong(rank.rank(index)); return small.getLong(index - rank.rank(index)); }
if (!trie.getBoolean(q)) return index; p = q; if (!trie.getBoolean(++p)) return index; r++;
/** Low-level access to the output of this function. * * <p>This method makes it possible to build several kind of functions on the same {@link ChunkedHashStore} and * then retrieve the resulting values by generating a single triple of hashes. The method * {@link TwoStepsMWHCFunction#getLong(Object)} is a good example of this technique. * * @param triple a triple generated as documented in {@link ChunkedHashStore}. * @return the output of the function. */ public long getLongByTriple(final long[] triple) { if (n == 0) return defRetValue; final int[] e = new int[3]; final int chunk = chunkShift == Long.SIZE ? 0 : (int)(triple[0] >>> chunkShift); final long chunkOffset = offset[chunk]; HypergraphSorter.tripleToEdge(triple, seed[chunk], (int)(offset[chunk + 1] - chunkOffset), e); final long e0 = e[0] + chunkOffset, e1 = e[1] + chunkOffset, e2 = e[2] + chunkOffset; if (e0 == -1) return defRetValue; final long result = rank == null ? data.getLong(e0) ^ data.getLong(e1) ^ data.getLong(e2) : (marker.getBoolean(e0) ? data.getLong(rank.rank(e0)) : 0) ^ (marker.getBoolean(e1) ? data.getLong(rank.rank(e1)) : 0) ^ (marker.getBoolean(e2) ? data.getLong(rank.rank(e2)) : 0); if (signatureMask == 0) return result; // Out-of-set strings can generate bizarre 3-hyperedges. if (signatures != null) return result >= n || signatures.getLong(result) != (triple[0] & signatureMask) ? defRetValue : result; else return ((result ^ triple[0]) & signatureMask) != 0 ? defRetValue : 1; }
/** Low-level access to the output of this function. * * <p>This method makes it possible to build several kind of functions on the same {@link ChunkedHashStore} and * then retrieve the resulting values by generating a single triple of hashes. The method * {@link TwoStepsGOV3Function#getLong(Object)} is a good example of this technique. * * @param triple a triple generated as documented in {@link ChunkedHashStore}. * @return the output of the function. */ public long getLongByTriple(final long[] triple) { if (n == 0) return defRetValue; final int[] e = new int[3]; final int chunk = chunkShift == Long.SIZE ? 0 : (int)(triple[0] >>> chunkShift); final long chunkOffset = offsetAndSeed[chunk] & OFFSET_MASK; final int numVariables = (int)((offsetAndSeed[chunk + 1] & OFFSET_MASK) - chunkOffset); if (numVariables == 0) return defRetValue; Linear3SystemSolver.tripleToEquation(triple, offsetAndSeed[chunk] & ~OFFSET_MASK, numVariables, e); final long e0 = e[0] + chunkOffset, e1 = e[1] + chunkOffset, e2 = e[2] + chunkOffset; final long result = rank == null ? data.getLong(e0) ^ data.getLong(e1) ^ data.getLong(e2) : (marker.getBoolean(e0) ? data.getLong(rank.rank(e0)) : 0) ^ (marker.getBoolean(e1) ? data.getLong(rank.rank(e1)) : 0) ^ (marker.getBoolean(e2) ? data.getLong(rank.rank(e2)) : 0); if (signatureMask == 0) return result; if (signatures != null) return result >= n || signatures.getLong(result) != (triple[0] & signatureMask) ? defRetValue : result; else return ((result ^ triple[0]) & signatureMask) != 0 ? defRetValue : 1; }
@Override @SuppressWarnings("unchecked") public long getLong(final Object o) { if (n == 0) return defRetValue; final int[] e = new int[3]; final long[] h = new long[3]; Hashes.spooky4(transform.toBitVector((T)o), globalSeed, h); final int chunk = chunkShift == Long.SIZE ? 0 : (int)(h[0] >>> chunkShift); final long chunkOffset = offset[chunk]; HypergraphSorter.tripleToEdge(h, seed[chunk], (int)(offset[chunk + 1] - chunkOffset), e); if (e[0] == -1) return defRetValue; final long e0 = e[0] + chunkOffset, e1 = e[1] + chunkOffset, e2 = e[2] + chunkOffset; final long result = rank == null ? data.getLong(e0) ^ data.getLong(e1) ^ data.getLong(e2) : (marker.getBoolean(e0) ? data.getLong(rank.rank(e0)) : 0) ^ (marker.getBoolean(e1) ? data.getLong(rank.rank(e1)) : 0) ^ (marker.getBoolean(e2) ? data.getLong(rank.rank(e2)) : 0); if (signatureMask == 0) return result; // Out-of-set strings can generate bizarre 3-hyperedges. if (signatures != null) return result >= n || ((signatures.getLong(result) ^ h[0]) & signatureMask) != 0 ? defRetValue : result; else return ((result ^ h[0]) & signatureMask) != 0 ? defRetValue : 1; }
/** Returns the exit node of a given bit vector. * * @param v a bit vector. * @param state the hash state of <code>v</code> precomputed by {@link Hashes#preprocessMurmur(BitVector, long)}. * @return the exit node of <code>v</code>. */ private ExitData<T> getExitNode(final LongArrayBitVector v, final long[] state) { if (size == 0) throw new IllegalStateException(); if (size == 1) return new ExitData<>(root, v.longestCommonPrefixLength(root.extent(transform))); if (DDEBUG) System.err.println("getExitNode(" + v + ")"); final long length = v.length(); // This can be the exit node of v, the parex node of v, or something completely wrong. InternalNode<T> parexOrExitNode = fatBinarySearch(v, state, null, false, -1, length); // This will contain the exit node if parexOrExitNode contains the correct parex node. Node<T> candidateExitNode = parexOrExitNode.extentLength < length && v.getBoolean(parexOrExitNode.extentLength) ? parexOrExitNode.right : parexOrExitNode.left; /* This lcp length makes it possible to compute the length of the lcp between v and * parexOrExitNode by minimisation with the extent length, as necessarily the extent of * candidateExitNode is an extension of the extent of parexOrExitNode. */ long lcpLength = v.longestCommonPrefixLength(candidateExitNode.extent(transform)); // In this case the fat binary search gave us the correct parex node. if (candidateExitNode.isExitNodeOf(length, lcpLength, transform)) return new ExitData<>(candidateExitNode, lcpLength); // In this case the fat binary search gave us the correct exit node. lcpLength = Math.min(parexOrExitNode.extentLength, lcpLength); if (parexOrExitNode.isExitNodeOf(length, lcpLength, transform)) return new ExitData<>(parexOrExitNode, lcpLength); // Otherwise, something went horribly wrong. We restart in exact mode. parexOrExitNode = fatBinarySearch(v, state, null, true, -1, length); candidateExitNode = parexOrExitNode.extent(transform).isProperPrefix(v) ? parexOrExitNode.extentLength < length && v.getBoolean(parexOrExitNode.extentLength) ? parexOrExitNode.right : parexOrExitNode.left : parexOrExitNode; return new ExitData<>(candidateExitNode, v.longestCommonPrefixLength(candidateExitNode.extent(transform))); }
if (pl != null) pl.lightUpdate(); if (olderNodeFound.getBoolean(currentNode)) { final int parentNode = nodeStack.topInt(); final int currentNodeStatus = status[currentNode]; if (computeBuckets && nonBuckets.getBoolean(currentNode)) nonBuckets.set(parentNode); final boolean notABucket = computeBuckets ? nonBuckets.getBoolean(currentNode) : false; numberOfComponents++; int z;
Node<T> candidateExitNode = parexOrExitNode.extentLength < length && v.getBoolean(parexOrExitNode.extentLength) ? parexOrExitNode.right : parexOrExitNode.left; candidateExitNode = parexOrExitNode.extentLength < length && v.getBoolean(parexOrExitNode.extentLength) ? parexOrExitNode.right : parexOrExitNode.left; lcpLength = v.longestCommonPrefixLength(candidateExitNode.extent(transform));
if (computeBuckets && nonBuckets.getBoolean(currentNode)) nonBuckets.set(parentNode); final boolean notABucket = computeBuckets ? nonBuckets.getBoolean(currentNode) : false; numberOfComponents++; int z;