001 package calhoun.seq;
002
003 import calhoun.util.Assert;
004 import calhoun.util.PrimeUtil;
005
006 public class RepeatedSubsequence {
007
008 /** Test if infinite repetitions of a and b can be aligned */
009 public static boolean isRollingMatch(String a, String b) {
010 int len = a.length();
011 if(len != b.length()) {
012 return false;
013 }
014 if(a.equals(b)) {
015 return true;
016 }
017 StringBuffer sb = new StringBuffer(a);
018 for(int i = 1; i<len; ++i) {
019 for(int j=0; j<len;++j) {
020 sb.setCharAt(j, a.charAt((i+j)%len));
021 }
022 if(sb.toString().equals(b)) {
023 return true;
024 }
025 }
026 return false;
027 }
028
029 /** Returns the largest repeated subsequence in a given string. */
030 public static String calc(String seq) {
031
032 // Pos is the end of the shortest repeat found so far. starts as being the whole length of the sequence.
033 int pos = seq.length();
034
035 // Prime our indexes with the original sequence
036 int maxPrime = seq.length()/2+1;
037
038 // Get list of all possible prime factors
039 int[] primes = PrimeUtil.primesToAtLeastN(maxPrime);
040
041 // Iterate up the list of primes (start at 2)
042 for(int i = 1; primes[i] <= maxPrime; ++i) {
043 // While the current repeat length is divisible by the current prime
044 while(pos%primes[i] == 0) {
045 boolean repeat = checkRepeat(seq, pos/primes[i], primes[i]);
046 if(repeat) {
047 // If it is identical, choose the first section and attempt to split that
048 pos = pos/primes[i];
049 }
050 else {
051 // If it is not, try the next prime
052 break;
053 }
054 }
055 }
056
057 String ret = seq.substring(0, pos);
058 // Also check for all the same if we got this far
059 if(checkRepeat(ret, 1, ret.length())) {
060 ret = ret.substring(0,1);
061 }
062
063 // Verify results.
064 Assert.a(checkRepeat(seq, ret.length(), seq.length()/ret.length()));
065 return ret;
066 }
067
068 /** Checks to see if the given sequence begins with n repeats, each of length l. */
069 public static boolean checkRepeat(String s, int l, int n) {
070 for(int i = 0; i<l; ++i) {
071 char c = s.charAt(i);
072 for(int j = 1; j<n; ++j) {
073 if (c != s.charAt(i+j*l))
074 return false;
075 }
076 }
077 return true;
078 }
079 }