Skip to content

Instantly share code, notes, and snippets.

@gebrkn
Last active February 27, 2016 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gebrkn/8b73949295853bdaf2b9 to your computer and use it in GitHub Desktop.
Save gebrkn/8b73949295853bdaf2b9 to your computer and use it in GitHub Desktop.
################################################
# that's what you guys wrote
################################################
import itertools as it
import operator as op
def test_evgeny_kluev_A(a, b):
equals = it.imap(op.eq, a, b) # compare lists
e1, e2 = it.tee(equals)
l = it.chain(e1, [True])
r = it.chain([True], e2)
borders = it.imap(op.ne, l, r) # delimit equal/non-equal intervals
ranges = list(it.islice(it.compress(it.count(), borders), 5))
if len(ranges) == 4:
n1, m1 = ranges[0], ranges[1]
n2, m2 = ranges[2], ranges[3]
elif len(ranges) == 2:
n1, m1 = ranges[0], len(a) // 2
n2, m2 = len(a) // 2, ranges[1]
else:
return None
if n1 == len(a) - m2 and m1 == len(a) - n2 \
and a[n1:m1] == b[n2:m2] and b[n1:m1] == a[n2:m2]:
return (n1, m1)
def test_evgeny_kluev_B(a, b):
equals = it.imap(op.eq, a, b[:len(a) // 2]) # compare half-lists
e1, e2 = it.tee(equals)
l = it.chain(e1, [True])
r = it.chain([True], e2)
borders = it.imap(op.ne, l, r) # delimit equal/non-equal intervals
ranges = list(it.islice(it.compress(it.count(), borders), 2))
if len(ranges) != 2:
return None
n, m = ranges[0], ranges[1]
nr, mr = len(a) - n, len(a) - m
if a[n:m] == b[mr:nr] and b[n:m] == a[mr:nr] \
and a[m:mr] == b[m:mr] and a[nr:] == b[nr:]:
return (n, m)
def test_evgeny_kluev_C(a, b):
length = len(a)
half = length // 2
mismatches = it.imap(op.ne, a, b[:half]) # compare half-lists
try:
n = next(it.compress(it.count(), mismatches))
nr = length - n
mr = a.index(b[n], half, nr)
m = length - mr
except StopIteration: return None
except ValueError: return None
if a[n:m] == b[mr:nr] and b[n:m] == a[mr:nr] \
and a[m:mr] == b[m:mr] and a[nr:] == b[nr:]:
return (n, m)
def test_roottwo(a, b):
sz = len(a)
ds = list(it.compress(it.count(), map(op.ne, a[:sz//2], b[:sz//2])))
n,m = ds[0], ds[-1]+1
if a[n:m] == b[sz-m:sz-n] and b[n:m] == a[sz-m:sz-n] and len(ds) == m - n:
return n,m
else:
return None
def test_tom_karzes(a, b):
cnt = len(a)
ml = [a[i] == b[i] for i in range(cnt)]
sl = [i for i in range(cnt) if (i == 0 or ml[i-1]) and not ml[i]]
el = [i+1 for i in range(cnt) if not ml[i] and (i == cnt-1 or ml[i+1])]
assert(len(sl) == len(el))
range_cnt = len(sl)
if range_cnt == 1:
start1 = sl[0]
end2 = el[0]
if (end2 - start1) % 2 != 0:
return None
end1 = (start1 + end2) // 2
start2 = end1
elif range_cnt == 2:
start1, start2 = sl
end1, end2 = el
else:
return None
if end1 - start1 != end2 - start2:
return None
if start1 != cnt - end2:
return None
if a[start1:end1] != b[start2:end2]:
return None
if b[start1:end1] != a[start2:end2]:
return None
return start1, end1
def test_alexis(A, B):
same = True
for i, (a, b) in enumerate(zip(A,B)):
if same and a != b: # Found the start of a presumed transposition
same = False
n = i
firstval = a # First element of the transposed piece
elif (not same) and (a == b or b == firstval): # end of the transposition
m = i
break
# Construct the transposed string, compare it to B
origin = A[n:m]
if n == 0: # swap begins at the edge
dest = A[-m:]
B_expect = dest + A[m:-m] + origin
else:
dest = A[-m:-n]
B_expect = A[:n] + dest + A[m:-m] + origin + A[-n:]
if B_expect == B:
return n, m
def test_ian(A, B):
Al = A[:len(A)//2]
Ar = A[len(A)//2:]
Bl = B[:len(B)//2]
Br = B[len(B)//2:]
la = len(Al)
L = len(A)
for i in range(len(Al)):
lai = la - i
for j in range(1, lai + 1):
k = lai - j
if Al[i] != Br[k] or Ar[k] != Bl[i]: #the key for efficient computation is here: do not proceed unnecessarily
continue
n = i
m = i + j
if A[n:m] == B[L-m:L-n] and B[n:m] == A[L-m:L-n]: #possibly symmetric
if A[0:n] == B[0:n] and A[m:L-m] == B[m:L-m] and A[L-n:] == B[L-n:]:
return n, m
return None
def test_viraptor(A, B):
L = len(A)
Br = B[L//2:]+B[:L//2]
same_full = [a==b for (a,b) in zip(A, Br)]
same_part = [a+b for (a,b) in zip(same_full[L//2:], same_full[:L//2])]
for n, vn in enumerate(same_part):
if vn != 2:
continue
m = n
for vm in same_part[n+1:]:
if vm != 2:
break
m+=1
if m>n:
return n, m + 1
def test_austin_hastings(a, b):
assert len(a) == len(b)
assert set(a) == set(b)
assert len(set(a)) == len(a)
length = len(a)
assert length % 2 == 0
half = length // 2
b_loc = {bi:n for n,bi in enumerate(b)}
for n,ai in enumerate(a[:half]):
L_n = length - 1 - n # L - n
L_m = b_loc[ai] # L - m (speculative)
if L_m < half: # Sanity: bail if on wrong side
continue
m = b_loc[a[L_n]] # If A[n] starts range, A[m] ends it.
if m < n or m > half: # Sanity: bail if backwards or wrong side
continue
left = slice(n, m+1)
right = slice(L_m, L_n+1)
if a[left] == b[right] and \
b[left] == a[right]:
return n, m + 1
return None
def test_peter_wood(A, B):
n = next(index for (index, (a, b)) in enumerate(zip(A, B))
if a != b)
m = n + sum(1 for a, b in zip(A, B) if a != b) / 2
if A[n:m] == B[-m:-n] and B[n:m] == A[-m:-n]:
return n, m
def test_jared_goguen(a, b):
L = len(a)
H = L//2
n, m = 0, H-1
# find the first difference in the left-side
while n < H:
if a[n] != b[n]: break
n += 1
else: return
# find the last difference in the left-side
while m > -1:
if a[m] != b[m]: break
m -= 1
else: return
# for slicing, we want end_index+1
m += 1
# compare each slice for equality
# order: beginning, block 1, block 2, middle, end
if (a[0:n] == b[0:n] and \
a[n:m] == b[L-m:L-n] and \
b[n:m] == a[L-m:L-n] and \
a[m:L-m] == b[m:L-m] and \
a[L-n:L] == b[L-n:L]):
return n, m
def test_jason_herbburn(a, b):
i_zip = list(enumerate(zip(a, b)))
llen = len(a)
hp = llen // 2
def find_index(i_zip):
for i, (x, y) in i_zip:
if x != y:
return i
return i_zip[0][0]
# n and m are determined by the unmoved items:
n = find_index(i_zip[:hp])
p = find_index(i_zip[hp:])
m = llen - p
q = llen - n
# Symmetric?
if a[:n] + a[p:q] + a[m:p] + a[n:m] + a[q:] != b:
return None
return n, m
################################################
# test facility
################################################
from itertools import permutations
from time import time
def symmetries(A):
""" Enumerate all symmetries for A."""
L = len(A)
k = L // 2
d = {}
for n in range(k):
for m in range(n + 1, k + 1):
b = list(A)
b[n:m], b[L-m:L-n] = b[L-m:L-n], b[n:m]
d[''.join(b)] = n, m
return d
def test(A, syms, fn):
# test positives
for B, q in syms.items():
p = fn(list(A), list(B))
assert p == q, [p, 'should be equal to', q, 'for', B]
# test negatives
for p in permutations(A):
B = ''.join(p)
if A == B or B in syms:
continue
p = fn(list(A), list(B))
assert not p, [p, 'should be None', 'for', B]
def run(fns, A, print_err=True):
print '\ntesting', A, 'L=', len(A)
syms = symmetries(A)
for name, fn in fns:
ts = time()
try:
test(A, syms, fn)
except AssertionError as e:
if print_err:
print '\t', name, 'ERR', e.message
except Exception as e:
if print_err:
print '\t', name, 'Exception', e.message
else:
print '\t', name, 'ok in', '%.4fs' % (time() - ts)
fns = sorted(x for x in vars().items() if x[0].startswith('test_'))
# correctness
for A in '01', '0123', '012345', '01234567':
run(fns, A, print_err=True)
# timings
for A in ['0123456789']:
run(fns, A, print_err=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment