package bgu.bio.algorithms.alignment;
import gnu.trove.list.array.TCharArrayList;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.map.hash.TLongDoubleHashMap;
public class CacheMemorySequenceAlignment implements SequenceAlignment {
public static final int prime = 17;
private SequenceAlignment aligner;
private final int maxSize;
private TIntObjectHashMap<TIntObjectHashMap<TLongDoubleHashMap>> map;
private double ans;
private int len1;
private int len2;
private boolean usedCache;
public CacheMemorySequenceAlignment(int maxSize, SequenceAlignment aligner) {
this.aligner = aligner;
this.maxSize = maxSize;
map = new TIntObjectHashMap<TIntObjectHashMap<TLongDoubleHashMap>>();
}
@Override
public void setSequences(String str1, String str2) {
if (str2.length() < str1.length()) {
String temp = str2;
str2 = str1;
str1 = temp;
}
len1 = str1.length();
len2 = str2.length();
if (len1 > maxSize || len2 > maxSize) {
aligner.setSequences(str1, str2);
aligner.buildMatrix();
ans = aligner.getAlignmentScore();
usedCache = false;
} else {
TIntObjectHashMap<TLongDoubleHashMap> lev1 = this.map.get(len1);
if (lev1 == null) {
lev1 = new TIntObjectHashMap<TLongDoubleHashMap>();
map.put(len1, lev1);
}
TLongDoubleHashMap lev2 = lev1.get(len2);
if (lev2 == null) {
lev2 = new TLongDoubleHashMap();
lev1.put(len2, lev2);
}
final long key = hash(str1, str2);
if (!lev2.contains(key)) {
aligner.setSequences(str1, str2);
aligner.buildMatrix();
ans = aligner.getAlignmentScore();
lev2.put(key, ans);
// if the same length hash them both
if (str1.length() == str2.length()) {
lev2.put(hash(str2, str1), ans);
}
usedCache = false;
} else {
ans = lev2.get(key);
usedCache = true;
}
}
}
@Override
public void setSequences(char[] str1, char[] str2) {
setSequences(str1, str1.length, str2, str2.length);
}
@Override
public void setSequences(char[] str1, int size1, char[] str2, int size2) {
if (str2.length < str1.length) {
char[] temp = str2;
str2 = str1;
str1 = temp;
int tmp = size2;
size2 = size1;
size1 = tmp;
}
len1 = size1;
len2 = size2;
if (len1 > maxSize || len2 > maxSize) {
aligner.setSequences(str1, str2);
aligner.buildMatrix();
ans = aligner.getAlignmentScore();
usedCache = false;
} else {
TIntObjectHashMap<TLongDoubleHashMap> lev1 = this.map.get(len1);
if (lev1 == null) {
lev1 = new TIntObjectHashMap<TLongDoubleHashMap>();
map.put(len1, lev1);
}
TLongDoubleHashMap lev2 = lev1.get(len2);
if (lev2 == null) {
lev2 = new TLongDoubleHashMap();
lev1.put(len2, lev2);
}
final long key = hash(str1, str2);
if (!lev2.contains(key)) {
aligner.setSequences(str1, str2);
aligner.buildMatrix();
ans = aligner.getAlignmentScore();
lev2.put(key, ans);
// if the same length hash them both
if (len1 == len2) {
lev2.put(hash(str2, str1), ans);
}
usedCache = false;
} else {
ans = lev2.get(key);
usedCache = true;
}
}
}
@Override
public void setSequences(TCharArrayList str1, TCharArrayList str2) {
if (str2.size() < str1.size()) {
TCharArrayList temp = str2;
str2 = str1;
str1 = temp;
}
aligner.setSequences(str1, str2);
len1 = str1.size();
len2 = str2.size();
if (len1 > maxSize || len2 > maxSize) {
aligner.setSequences(str1, str2);
aligner.buildMatrix();
ans = aligner.getAlignmentScore();
usedCache = false;
} else {
TIntObjectHashMap<TLongDoubleHashMap> lev1 = this.map.get(len1);
if (lev1 == null) {
lev1 = new TIntObjectHashMap<TLongDoubleHashMap>();
map.put(len1, lev1);
}
TLongDoubleHashMap lev2 = lev1.get(len2);
if (lev2 == null) {
lev2 = new TLongDoubleHashMap();
lev1.put(len2, lev2);
}
final long key = hash(str1, str2);
if (!lev2.contains(key)) {
aligner.setSequences(str1, str2);
aligner.buildMatrix();
ans = aligner.getAlignmentScore();
lev2.put(key, ans);
// if the same length hash them both
if (str1.size() == str2.size()) {
lev2.put(hash(str2, str1), ans);
}
usedCache = false;
} else {
ans = lev2.get(key);
usedCache = true;
}
}
}
private long hash(TCharArrayList str1, TCharArrayList str2) {
long h = 0;
for (int i = 0; i < str1.size(); i++) {
h = prime * h + str1.getQuick(i);
}
for (int i = 0; i < str2.size(); i++) {
h = prime * h + str2.getQuick(i);
}
return h;
}
private long hash(String str1, String str2) {
long h = 0;
for (int i = 0; i < str1.length(); i++) {
h = prime * h + str1.charAt(i);
}
for (int i = 0; i < str2.length(); i++) {
h = prime * h + str2.charAt(i);
}
return h;
}
private long hash(char[] str1, char[] str2) {
long h = 0;
for (int i = 0; i < str1.length; i++) {
h = prime * h + str1[i];
}
for (int i = 0; i < str2.length; i++) {
h = prime * h + str2[i];
}
return h;
}
@Override
public void buildMatrix() {
}
@Override
public double getAlignmentScore() {
return ans;
}
@Override
public void setNormFactor(double factor) {
}
/**
* <b>USED ONLY FOR TESTING</b>
*
* @return if the last call used the buffer or not.
*/
public boolean getUsedCache() {
return this.usedCache;
}
@Override
public String[] getAlignment() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Need to implement");
}
@Override
public CacheMemorySequenceAlignment cloneAligner() {
CacheMemorySequenceAlignment other = new CacheMemorySequenceAlignment(
maxSize, aligner.cloneAligner());
return other;
}
}