Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -0,0 +1,21 @@
lcs{
⎕IO0
betterof{(</+/¨ ) } ⍝ better of 2 selections
cmbn{,.,/(),} ⍝ combine lists
rr{/>/1 ¯1[1]¨} ⍝ rising rows
hmrr{/(rr )/=\} ⍝ has monotonically rising rows
rnbc{{/}¨[0]×} ⍝ row numbers by column
validhmrrcmbnrnbc ⍝ any valid solutions?
a w(</¨ ) ⍝ longest first
matchesa.=w
aps{[;+]}{(/2)2*} ⍝ all possible subsequences
swps{/~(~)} ⍝ subsequences with possible solns
ssttmatches swps apsw ⍝ subsequences to try
w/{
0 ⍝ initial selection
(+/)+/[;0]: ⍝ no scope to improve
this betterof{×valid /matches}[;0] ⍝ try to improve
1=1:this ⍝ nothing left to try
this 1[1] ⍝ keep looking
}sstt
}

View file

@ -0,0 +1,154 @@
#include <stdint.h>
#include <string>
#include <memory> // for shared_ptr<>
#include <iostream>
#include <deque>
#include <map>
#include <algorithm> // for lower_bound()
using namespace std;
class LCS {
protected:
// This linked list class is used to trace the LCS candidates
class Pair {
public:
uint32_t index1;
uint32_t index2;
shared_ptr<Pair> next;
Pair(uint32_t index1, uint32_t index2, shared_ptr<Pair> next = nullptr)
: index1(index1), index2(index2), next(next) {
}
static shared_ptr<Pair> Reverse(const shared_ptr<Pair> pairs) {
shared_ptr<Pair> head = nullptr;
for (auto next = pairs; next != nullptr; next = next->next)
head = make_shared<Pair>(next->index1, next->index2, head);
return head;
}
};
typedef deque<shared_ptr<Pair>> PAIRS;
typedef deque<uint32_t> THRESHOLD;
typedef deque<uint32_t> INDEXES;
typedef map<char, INDEXES> CHAR2INDEXES;
typedef deque<INDEXES*> MATCHES;
// return the LCS as a linked list of matched index pairs
uint64_t LCS::Pairs(MATCHES& matches, shared_ptr<Pair> *pairs) {
auto trace = pairs != nullptr;
PAIRS traces;
THRESHOLD threshold;
//
//[Assert]After each index1 iteration threshold[index3] is the least index2
// such that the LCS of s1[0:index1] and s2[0:index2] has length index3 + 1
//
uint32_t index1 = 0;
for (const auto& it1 : matches) {
if (!it1->empty()) {
auto dq2 = *it1;
auto limit = threshold.end();
for (auto it2 = dq2.begin(); it2 != dq2.end(); it2++)
{
// Each of the index1, index2 pairs considered here correspond to a match
auto index2 = *it2;
//
// Note: The index2 values are monotonically decreasing, which allows the
// thresholds to be updated in place. Montonicity allows a binary search,
// implemented here by std::lower_bound()
//
limit = lower_bound(threshold.begin(), limit, index2);
auto index3 = distance(threshold.begin(), limit);
//
// Look ahead to the next index2 value to optimize space used in the Hunt
// and Szymanski algorithm. If the next index2 is also an improvement on
// the value currently held in threshold[index3], a new Pair will only be
// superseded on the next index2 iteration.
//
// Depending on match redundancy, the number of Pair constructions may be
// divided by factors ranging from 2 up to 10 or more.
//
auto skip = it2 + 1 != dq2.end() &&
(limit == threshold.begin() || *(limit - 1) < *(it2 + 1));
if (skip) continue;
if (limit == threshold.end()) {
// insert case
threshold.push_back(index2);
if (trace) {
auto prefix = index3 > 0 ? traces[index3 - 1] : nullptr;
auto last = make_shared<Pair>(index1, index2, prefix);
traces.push_back(last);
}
}
else if (index2 < *limit) {
// replacement case
*limit = index2;
if (trace) {
auto prefix = index3 > 0 ? traces[index3 - 1] : nullptr;
auto last = make_shared<Pair>(index1, index2, prefix);
traces[index3] = last;
}
}
} // next index2
}
index1++;
} // next index1
if (trace) {
auto last = traces.size() > 0 ? traces.back() : nullptr;
// Reverse longest back-trace
*pairs = Pair::Reverse(last);
}
auto length = threshold.size();
return length;
}
//
// Match() avoids incurring m*n comparisons by using the associative memory
// implemented by CHAR2INDEXES to achieve O(m+n) performance, where m and n
// are the input lengths.
//
// The symbol space is sparse in the case of records; so, the lookup time is
// at most O(log(m+n)). The lookup time can be assumed constant in the case
// of characters.
//
void Match(CHAR2INDEXES& indexes, MATCHES& matches,
const string& s1, const string& s2) {
uint32_t index = 0;
for (const auto& it : s2)
indexes[it].push_front(index++);
for (const auto& it : s1) {
auto& dq2 = indexes[it];
matches.push_back(&dq2);
}
}
string Select(shared_ptr<Pair> pairs, uint64_t length,
bool right, const string& s1, const string& s2) {
string buffer;
buffer.reserve(length);
for (auto next = pairs; next != nullptr; next = next->next) {
auto c = right ? s2[next->index2] : s1[next->index1];
buffer.push_back(c);
}
return buffer;
}
public:
string Correspondence(const string& s1, const string& s2) {
CHAR2INDEXES indexes;
MATCHES matches; // holds references into indexes
Match(indexes, matches, s1, s2);
shared_ptr<Pair> pairs; // obtain the LCS as index pairs
auto length = Pairs(matches, &pairs);
return Select(pairs, length, false, s1, s2);
}
};

View file

@ -0,0 +1,3 @@
LCS lcs;
auto s = lcs.Correspondence(s1, s2);
cout << s << endl;

View file

@ -0,0 +1,14 @@
(defmacro mem-defun (name args body)
(let ((hash-name (gensym)))
`(let ((,hash-name (make-hash-table :test 'equal)))
(defun ,name ,args
(or (gethash (list ,@args) ,hash-name)
(setf (gethash (list ,@args) ,hash-name)
,body))))))
(mem-defun lcs (xs ys)
(labels ((longer (a b) (if (> (length a) (length b)) a b)))
(cond ((or (null xs) (null ys)) nil)
((equal (car xs) (car ys)) (cons (car xs) (lcs (cdr xs) (cdr ys))))
(t (longer (lcs (cdr xs) ys)
(lcs xs (cdr ys)))))))

View file

@ -0,0 +1,3 @@
(coerce (lcs (coerce "thisisatest" 'list) (coerce "testing123testing" 'list)) 'string))))
"tsitest"

View file

@ -1,6 +1,6 @@
import std.stdio, std.array;
T[] lcs(T)(in T[] a, in T[] b) pure nothrow {
T[] lcs(T)(in T[] a, in T[] b) pure nothrow @safe {
if (a.empty || b.empty) return null;
if (a[0] == b[0])
return a[0] ~ lcs(a[1 .. $], b[1 .. $]);

View file

@ -1,7 +1,6 @@
import std.stdio, std.algorithm, std.range, std.array, std.string,
std.typecons;
import std.stdio, std.algorithm, std.range, std.array, std.string, std.typecons;
uint[] lensLCS(R)(R xs, R ys) pure nothrow {
uint[] lensLCS(R)(R xs, R ys) pure nothrow @safe {
auto prev = new typeof(return)(1 + ys.length);
auto curr = new typeof(return)(1 + ys.length);
@ -9,9 +8,7 @@ uint[] lensLCS(R)(R xs, R ys) pure nothrow {
swap(curr, prev);
size_t i = 0;
foreach (immutable y; ys) {
curr[i + 1] = (x == y)
? prev[i] + 1
: max(curr[i], prev[i + 1]);
curr[i + 1] = (x == y) ? prev[i] + 1 : max(curr[i], prev[i + 1]);
i++;
}
}
@ -20,7 +17,7 @@ uint[] lensLCS(R)(R xs, R ys) pure nothrow {
}
void calculateLCS(T)(in T[] xs, in T[] ys, bool[] xs_in_lcs,
in size_t idx=0) pure nothrow {
in size_t idx=0) pure nothrow @safe {
immutable nx = xs.length;
immutable ny = ys.length;
@ -36,33 +33,27 @@ void calculateLCS(T)(in T[] xs, in T[] ys, bool[] xs_in_lcs,
const xe = xs[mid .. $];
immutable ll_b = lensLCS(xb, ys);
// retro is slow with dmd.
const ll_e = lensLCS(xe.retro, ys.retro);
const ll_e = lensLCS(xe.retro, ys.retro); // retro is slow with dmd.
//immutable k = iota(ny + 1)
// .reduce!(max!(j => ll_b[j] + ll_e[ny - j]));
immutable k = iota(ny + 1)
.minPos!((i,j)=> tuple(ll_b[i] + ll_e[ny-i]) >
tuple(ll_b[j] + ll_e[ny-j]))[0];
.minPos!((i, j) => tuple(ll_b[i] + ll_e[ny - i]) >
tuple(ll_b[j] + ll_e[ny - j]))[0];
calculateLCS(xb, ys[0 .. k], xs_in_lcs, idx);
calculateLCS(xe, ys[k .. $], xs_in_lcs, idx + mid);
}
}
const(T)[] lcs(T)(in T[] xs, in T[] ys) pure /*nothrow*/ {
const(T)[] lcs(T)(in T[] xs, in T[] ys) pure /*nothrow*/ @safe {
auto xs_in_lcs = new bool[xs.length];
calculateLCS(xs, ys, xs_in_lcs);
return zip(xs, xs_in_lcs) // Not nothrow.
.filter!q{ a[1] }
.map!q{ a[0] }
.array;
return zip(xs, xs_in_lcs).filter!q{ a[1] }.map!q{ a[0] }.array; // Not nothrow.
}
string lcsString(in string s1, in string s2) pure /*nothrow*/ {
//return lcs(s1.representation, s2.representation).assumeChars;
return cast(string)lcs(s1.representation, s2.representation);
string lcsString(in string s1, in string s2) pure /*nothrow*/ @safe {
return lcs(s1.representation, s2.representation).assumeUTF;
}
void main() {

View file

@ -0,0 +1,23 @@
lcs(Xs0, Ys0) ->
CacheKey = {lcs_cache, Xs0, Ys0},
case get(CacheKey)
of undefined ->
Result =
case {Xs0, Ys0}
of {[], _} -> []
; {_, []} -> []
; {[Same | Xs], [Same | Ys]} ->
[Same | lcs(Xs, Ys)]
; {[_ | XsRest]=XsAll, [_ | YsRest]=YsAll} ->
A = lcs(XsRest, YsAll),
B = lcs(XsAll , YsRest),
case length(A) > length(B)
of true -> A
; false -> B
end
end,
undefined = put(CacheKey, Result),
Result
; Result ->
Result
end.

View file

@ -1,41 +1,42 @@
func lcs(a, b string) string {
aLen := len(a)
bLen := len(b)
lengths := make([][]int, aLen+1)
for i := 0; i <= aLen; i++ {
lengths[i] = make([]int, bLen+1)
}
// row 0 and column 0 are initialized to 0 already
arunes := []rune(a)
brunes := []rune(b)
aLen := len(arunes)
bLen := len(brunes)
lengths := make([][]int, aLen+1)
for i := 0; i <= aLen; i++ {
lengths[i] = make([]int, bLen+1)
}
// row 0 and column 0 are initialized to 0 already
for i := 0; i < aLen; i++ {
for j := 0; j < bLen; j++ {
if a[i] == b[j] {
lengths[i+1][j+1] = lengths[i][j]+1
} else if lengths[i+1][j] > lengths[i][j+1] {
lengths[i+1][j+1] = lengths[i+1][j]
} else {
lengths[i+1][j+1] = lengths[i][j+1]
}
}
}
for i := 0; i < aLen; i++ {
for j := 0; j < bLen; j++ {
if arunes[i] == brunes[j] {
lengths[i+1][j+1] = lengths[i][j] + 1
} else if lengths[i+1][j] > lengths[i][j+1] {
lengths[i+1][j+1] = lengths[i+1][j]
} else {
lengths[i+1][j+1] = lengths[i][j+1]
}
}
}
// read the substring out from the matrix
s := make([]byte, 0, lengths[aLen][bLen])
for x, y := aLen, bLen; x != 0 && y != 0; {
if lengths[x][y] == lengths[x-1][y] {
x--
} else if lengths[x][y] == lengths[x][y-1] {
y--
} else {
s = append(s, a[x-1])
x--
y--
}
}
// reverse string
r := make([]byte, len(s))
for i := 0; i < len(s); i++ {
r[i] = s[len(s)-1-i]
}
return string(r)
// read the substring out from the matrix
s := make([]rune, 0, lengths[aLen][bLen])
for x, y := aLen, bLen; x != 0 && y != 0; {
if lengths[x][y] == lengths[x-1][y] {
x--
} else if lengths[x][y] == lengths[x][y-1] {
y--
} else {
s = append(s, arunes[x-1])
x--
y--
}
}
// reverse string
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return string(s)
}

View file

@ -1,15 +1,20 @@
let lcs xs' ys' =
let xs = Array.of_list xs'
and ys = Array.of_list ys' in
let n = Array.length xs
and m = Array.length ys in
let a = Array.make_matrix (n+1) (m+1) [] in
for i = n-1 downto 0 do
for j = m-1 downto 0 do
a.(i).(j) <- if xs.(i) = ys.(j) then
xs.(i) :: a.(i+1).(j+1)
else
longest a.(i).(j+1) a.(i+1).(j)
done
done;
a.(0).(0)
let lcs xs ys =
let cache = Hashtbl.create 16 in
let rec lcs xs ys =
try Hashtbl.find cache (xs, ys) with
| Not_found ->
let result =
match xs, ys with
| [], _ -> []
| _, [] -> []
| x :: xs, y :: ys when x = y ->
x :: lcs xs ys
| _ :: xs_rest, _ :: ys_rest ->
let a = lcs xs_rest ys in
let b = lcs xs ys_rest in
if (List.length a) > (List.length b) then a else b
in
Hashtbl.add cache (xs, ys) result;
result
in
lcs xs ys

View file

@ -1,10 +1,15 @@
let list_of_string str =
let result = ref [] in
String.iter (fun x -> result := x :: !result)
str;
List.rev !result
let string_of_list lst =
let result = String.create (List.length lst) in
ignore (List.fold_left (fun i x -> result.[i] <- x; i+1) 0 lst);
result
let lcs xs' ys' =
let xs = Array.of_list xs'
and ys = Array.of_list ys' in
let n = Array.length xs
and m = Array.length ys in
let a = Array.make_matrix (n+1) (m+1) [] in
for i = n-1 downto 0 do
for j = m-1 downto 0 do
a.(i).(j) <- if xs.(i) = ys.(j) then
xs.(i) :: a.(i+1).(j+1)
else
longest a.(i).(j+1) a.(i+1).(j)
done
done;
a.(0).(0)

View file

@ -0,0 +1,10 @@
let list_of_string str =
let result = ref [] in
String.iter (fun x -> result := x :: !result)
str;
List.rev !result
let string_of_list lst =
let result = String.create (List.length lst) in
ignore (List.fold_left (fun i x -> result.[i] <- x; i+1) 0 lst);
result

View file

@ -3,12 +3,12 @@ irb(main):001:0> lcs('thisisatest', 'testing123testing')
=> "tsitest"
=end
def lcs(xstr, ystr)
return "" if xstr.empty? || ystr.empty?
return "" if xstr.empty? || ystr.empty?
x, xs, y, ys = xstr[0..0], xstr[1..-1], ystr[0..0], ystr[1..-1]
if x == y
x + lcs(xs, ys)
else
[lcs(xstr, ys), lcs(xs, ystr)].max_by {|x| x.size}
end
x, xs, y, ys = xstr[0..0], xstr[1..-1], ystr[0..0], ystr[1..-1]
if x == y
x + lcs(xs, ys)
else
[lcs(xstr, ys), lcs(xs, ystr)].max_by {|x| x.size}
end
end

View file

@ -1,11 +1,22 @@
class LcsWalker
class LCS
SELF, LEFT, UP, DIAG = [0,0], [0,-1], [-1,0], [-1,-1]
def initialize(matrix); @m, @i, @j = matrix, 0, 0; end
def valid?(i=@i, j=@j); i >= 0 && j >= 0; end
def match(c, d); @m[@i][@j] = compute_entry(c, d); end
def pos(i, j); @i, @j = i, j; end
def lookup(x, y); [@i+x, @j+y]; end
def initialize(a, b)
@m = Array.new(a.length) { Array.new(b.length) }
a.each_char.with_index do |x, i|
b.each_char.with_index do |y, j|
match(x, y, i, j)
end
end
end
def match(c, d, i, j)
@i, @j = i, j
@m[i][j] = compute_entry(c, d)
end
def lookup(x, y) [@i+x, @j+y] end
def valid?(i=@i, j=@j) i >= 0 && j >= 0 end
def peek(x, y)
i, j = lookup(x, y)
@ -17,10 +28,20 @@ class LcsWalker
end
def backtrack
Enumerator.new { |y| y << @i+1 if backstep while valid? }
@i, @j = @m.length-1, @m[0].length-1
y = []
y << @i+1 if backstep? while valid?
y.reverse
end
def backstep
def backtrack2
@i, @j = @m.length-1, @m[0].length-1
y = []
y << @j+1 if backstep? while valid?
[backtrack, y.reverse]
end
def backstep?
backstep = compute_backstep
@i, @j = lookup(*backstep)
backstep == DIAG
@ -34,3 +55,13 @@ class LcsWalker
end
end
end
def lcs(a, b)
walker = LCS.new(a, b)
walker.backtrack.map{|i| a[i]}.join
end
if $0 == __FILE__
puts lcs('thisisatest', 'testing123testing')
puts lcs("rosettacode", "raisethysword")
end

View file

@ -65,5 +65,4 @@ object LCS extends App {
println{val t = elapsed(s = lcsd(p._1,p._2))
"lcsd(\""+p._1+"\",\""+p._2+"\") = \""+s+"\" ("+t+" sec)"}
}
}