com.simiacryptus.util.binary.codes.HammingCode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-util Show documentation
Show all versions of java-util Show documentation
Miscellaneous utilities for Java 8
/*
* Copyright (c) 2019 by Andrew Charneski.
*
* The author licenses this file to you under the
* Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance
* with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.simiacryptus.util.binary.codes;
import com.simiacryptus.util.binary.BitInputStream;
import com.simiacryptus.util.binary.Bits;
import com.simiacryptus.util.binary.bitset.CountTreeBitsCollection;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
public class HammingCode> {
protected final TreeMap forwardIndex = new TreeMap();
protected final HashMap reverseIndex = new HashMap();
protected final HashMap weights = new HashMap();
protected final long totalWeight;
public HammingCode(final Collection> symbols) {
if (0 < symbols.size()) {
final TreeSet> assemblySet = new TreeSet>();
for (final HammingSymbol s : symbols) {
this.weights.put(s.key, s.count);
assemblySet.add(new SubCode(s.count, s.key));
}
while (assemblySet.size() > 1) {
final SubCode zero = assemblySet.pollFirst();
final SubCode one = assemblySet.pollFirst();
assemblySet.add(new SubCode(zero, one));
}
final SubCode root = assemblySet.first();
this.forwardIndex.putAll(root.codes);
this.reverseIndex.putAll(root.index);
totalWeight = root.count;
} else {
totalWeight = 0;
}
assert this.verifyIndexes();
assert this.forwardIndex.size() == symbols.size();
}
public static boolean isPrefixFreeCode(final Set keySet) {
final TreeSet check = new TreeSet();
for (final Bits code : keySet) {
final Bits ceiling = check.ceiling(code);
if (null != ceiling
&& (ceiling.startsWith(code) || code.startsWith(ceiling))) {
return false;
}
final Bits floor = check.floor(code);
if (null != floor && (floor.startsWith(code) || code.startsWith(floor))) {
return false;
}
check.add(code);
}
return true;
}
public int codeSize() {
return this.forwardIndex.size();
}
public T decode(final BitInputStream in) throws IOException {
Bits remainder = in.readAhead(0);
Entry entry = this.forwardIndex.floorEntry(remainder);
while (entry == null || !remainder.startsWith(entry.getKey())) {
remainder = in.readAhead();
entry = this.forwardIndex.floorEntry(remainder);
}
in.read(entry.getKey().bitLength);
return entry.getValue();
}
public Entry decode(final Bits data) {
if (null == data) {
throw new IllegalArgumentException();
}
Entry entry = this.forwardIndex.floorEntry(data);
// TestUtil.openJson(new JSONObject(forwardIndex));
if (entry != null && !data.startsWith(entry.getKey())) {
entry = null;
}
// assert(null != entry || verifyIndexes());
return entry;
}
public Bits encode(final T key) {
final Bits bits = this.reverseIndex.get(key);
assert null != bits || this.verifyIndexes();
return bits;
}
public SortedMap getCodes(final Bits fromKey) {
final Bits next = fromKey.next();
final SortedMap subMap = null == next ? this.forwardIndex
.tailMap(fromKey) : this.forwardIndex.subMap(fromKey, next);
return subMap;
}
public CountTreeBitsCollection getSetEncoder() {
return new HammingCodeCollection();
}
public CountTreeBitsCollection getSetEncoder(final BitInputStream data)
throws IOException {
return new HammingCodeCollection(data);
}
public CountTreeBitsCollection getSetEncoder(final byte[] data)
throws IOException {
return new HammingCodeCollection(data);
}
public Map getWeights() {
return Collections.unmodifiableMap(this.weights);
}
public boolean verifyIndexes() {
if (!isPrefixFreeCode(this.forwardIndex.keySet())) {
return false;
}
for (final Entry e : this.forwardIndex.entrySet()) {
if (!e.getKey().equals(this.reverseIndex.get(e.getValue()))) {
return false;
}
if (!e.getValue().equals(this.forwardIndex.get(e.getKey()))) {
return false;
}
}
for (final Entry e : this.reverseIndex.entrySet()) {
if (!e.getKey().equals(this.forwardIndex.get(e.getValue()))) {
return false;
}
if (!e.getValue().equals(this.reverseIndex.get(e.getKey()))) {
return false;
}
}
return this.reverseIndex.size() == this.forwardIndex.size();
}
public int totalWeight() {
// TODO Auto-generated method stub
return 0;
}
private static class SubCode> implements
Comparable> {
final long count;
final TreeMap codes;
final TreeMap index;
public SubCode(final long count, final X item) {
super();
this.count = count;
this.codes = new TreeMap();
this.index = new TreeMap();
this.codes.put(Bits.NULL, item);
this.index.put(item, Bits.NULL);
}
public SubCode(final SubCode zero, final SubCode one) {
super();
this.count = zero.count + one.count;
this.codes = new TreeMap();
this.index = new TreeMap();
for (final Entry e : zero.codes.entrySet()) {
assert !one.index.containsKey(e.getValue());
final Bits code = Bits.ZERO.concatenate(e.getKey());
this.assertNull(this.codes.put(code, e.getValue()));
this.assertNull(this.index.put(e.getValue(), code));
}
for (final Entry e : one.codes.entrySet()) {
assert !zero.index.containsKey(e.getValue());
final Bits code = Bits.ONE.concatenate(e.getKey());
this.assertNull(this.codes.put(code, e.getValue()));
this.assertNull(this.index.put(e.getValue(), code));
}
}
private void assertNull(final Object obj) {
assert null == obj;
}
@Override
public int compareTo(final SubCode o) {
if (this.count < o.count) {
return -1;
}
if (this.count > o.count) {
return 1;
}
final int compareTo = this.index.firstKey().compareTo(o.index.firstKey());
assert 0 != compareTo;
return compareTo;
}
}
public class HammingCodeCollection extends CountTreeBitsCollection {
public HammingCodeCollection() {
super();
}
public HammingCodeCollection(final BitInputStream data) throws IOException {
super(data);
}
public HammingCodeCollection(final byte[] data) throws IOException {
super(data);
}
@Override
public CodeType getType(final Bits bits) {
final Entry code = HammingCode.this.decode(bits);
if (null == code) {
return CodeType.Prefix;
}
assert bits.equals(code.getKey());
return CodeType.Terminal;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy