// to do: // - figure out what to do with #S var bwt = {} bwt.rotate_string = function(string, n) { var rv = [] for (var ii = 0; ii < string.length; ii++) { rv.push(string[(ii + n) % string.length]) } return rv.join('') } bwt.rotations = function(contents) { var rv = [] for (var ii = 0; ii < contents.length; ii++) rv.push(bwt.rotate_string(contents, ii)) return rv } bwt.highlighted_span = function(text, color) { var span = $('') span.css('background', color) span.text(text) return span } // I’m not proud of this code. It fills a
with a list of lines // of text. Optionally, it highlights the first column, the last // column, and/or the Nth row of the text, as specified by `pp`. bwt.set_matrix_contents = function(matrix, strings, pp) { if (!pp) pp = {} // parameters matrix.empty() var rv = $('') for (var ii = 0; ii < strings.length; ii++) { var string = strings[ii] if (pp.last_column_bg) string = string.slice(0, -1) if (pp.first_column_bg) { rv.append(bwt.highlighted_span(string[0], pp.first_column_bg)) string = string.slice(1) } if (pp.row_bg && (ii == pp.row_to_highlight)) { rv.append(bwt.highlighted_span(string, pp.row_bg)) } else { rv.append(document.createTextNode(string)) } if (pp.last_column_bg) { rv.append(bwt.highlighted_span(strings[ii].slice(-1), pp.last_column_bg)) } rv.append(document.createTextNode('\n')) } return rv.appendTo(matrix) } bwt.last_column = function(stringlist) { return $.map(stringlist, function(string) { return string[string.length-1] }).join('') } bwt.string$ = function(unit, repeats) { var rv = [] for (var ii = 0; ii < repeats; ii++) rv.push(unit) return rv.join('') } bwt.m2 = function(L, F) { var rv = [] for (var ii = 0; ii < L.length; ii++) rv.push(F[ii] + bwt.string$('?', L.length - 2) + L[ii]) return rv } bwt.mprime = function(L, F) { var rv = [] for (var ii = 0; ii < L.length; ii++) rv.push(L[ii] + F[ii] + bwt.string$('?', L.length - 2)) return rv } bwt.range = function(N) { var rv = [] for (var ii = 0; ii < N; ii++) rv.push(ii) return rv } bwt.set_table_row = function(row, contents) { // preserves first child (assuming it's a TH) var tr = row[0] var th = tr.firstChild while (th.nextSibling) tr.removeChild(th.nextSibling) for (var ii = 0; ii < contents.length; ii++) { var td = document.createElement('td') td.appendChild(document.createTextNode(contents[ii])) tr.appendChild(td) } } bwt.compute_k = function(string) { var rv = [] var ks = {} for (var ii = 0; ii < string.length; ii++) { var cc = string[ii] if (ks[cc] == undefined) ks[cc] = 0 rv.push(ks[cc]) ks[cc]++ } return rv } bwt.compute_TT = function(F, L) { // for all j ∊ [0,len(L)), L[TT[j]] = F[j] and k_L[TT[j]] = k_F[j] var k_F = bwt.compute_k(F) var k_L = bwt.compute_k(L) var pos = {} for (var ii = 0; ii < L.length; ii++) pos[L[ii] + k_L[ii]] = ii var TT = [] for (var jj = 0; jj < F.length; jj++) TT[jj] = pos[F[jj] + k_F[jj]] return TT } bwt.verify_TT = function(L, TT) { var rv = [] for (var ii = 0; ii < TT.length; ii++) rv.push(L[TT[ii]]) return rv } bwt.iterate_TT = function(j, TT) { var rv = [] for (var ii = 0; ii < TT.length; ii++) { rv.push(j) j = TT[j] } return rv } bwt.vec_index = function(table, indices) { var rv = [] for (var ii = 0; ii < indices.length; ii++) rv.push(table[indices[ii]]) return rv } bwt.make_timer = function(N) { var start = new Date() setTimeout(function(){ var result = "" + N + " " + (new Date() - start) + "\n" $('#timings')[0].value += result }, 0) } bwt.update_reverse_transform = function() { var L = $('#results').val() var chars = L.split(/|/) chars.sort() var F = chars.join('') $('#F').val(F) // XXX parseInt?? var idx = parseInt($('#index').val()) bwt.set_matrix_contents($('#M2'), bwt.m2(L, F), { row_to_highlight: idx, row_bg: 'tan', last_column_bg: 'wheat' }) bwt.set_matrix_contents($('#mprime'), bwt.mprime(L, F), { row_to_highlight: idx, row_bg: 'tan', first_column_bg: 'wheat' }) bwt.set_table_row($('#j'), bwt.range(L.length)) bwt.set_table_row($('#F_chars'), F) bwt.set_table_row($('#k_F'), bwt.compute_k(F)) bwt.set_table_row($('#L_chars'), L) bwt.set_table_row($('#k_L'), bwt.compute_k(L)) var TT = bwt.compute_TT(F, L) bwt.set_table_row($('#TT'), TT) bwt.set_table_row($('#L_TT_j'), bwt.verify_TT(L, TT)) var j_iter = bwt.iterate_TT(idx, TT) bwt.set_table_row($('#j_iter'), j_iter) bwt.set_table_row($('#F_j'), bwt.vec_index(F, j_iter)) bwt.set_table_row($('#TT_j'), bwt.vec_index(TT, j_iter)) } bwt.update = function(contents) { bwt.make_timer(contents.length) var rows = bwt.rotations(contents) bwt.set_matrix_contents($('#rotations_matrix'), rows) rows.sort() var idx = $.inArray(contents, rows) bwt.set_matrix_contents($('#sorted_matrix'), rows, { row_to_highlight: idx, row_bg: 'tan', last_column_bg: 'wheat' }) var L = bwt.last_column(rows) $('#results').val(L) $('#index').val(idx) bwt.update_reverse_transform() } bwt.value_to_update = null bwt._update = function() { if (bwt.value_to_update) bwt.update(bwt.value_to_update) bwt.value_to_update = null } bwt.pending_update = function(val) { bwt.value_to_update = val setTimeout(bwt._update, 0) return true } bwt.set_S = function(val) { $('#theinput').val(val) bwt.pending_update(val) } bwt.init = function() { $('#theinput').keyup(function () { bwt.pending_update(this.value) }) $('#results').keyup(function () { bwt.update_reverse_transform() }) $('#index').keyup(function () { bwt.update_reverse_transform() }) bwt.update($('#theinput').val()) } bwt.show_timings = function() { $('#timings').show() } $(document).ready(bwt.init)