# ties.py
# (c) 2013 Mikael Vejdemo-Johansson
# Released as CC-BY

import itertools
from scipy.special import binom

"""
Reproducing Fink & Mao is done by the following:

finkmao = classical(prototies(wtpairs(9)))
"""

def wtpairs(maxN,mod3=1):
    return [(i,n-i) for n in range(maxN)
            for i in range(n+1) if (n-2*i) % 3 == mod3]

def prototies(wtps):
    ret = []
    for (n,k) in wtps:
        if k==0:
            ret.append(['W']*(n+k))
            continue
        poss = itertools.combinations(range(n+k),k)
        for pos in poss:
            tie = ['W']*(n+k)
            for p in pos:
                tie[p] = 'T'
            ret.append(tie)
    return ret

def classical(protos):
    return [p for p in protos if len(p)>=2 and p[-2] == p[-1]]

def ktuckfinals(protos, k):
    def wort(t):
        if t == 'W':
            return 1
        elif t == 'T':
            return -1
        else:
            return 0
    def wmint(tt):
        return sum(map(wort,tt)) % 3
    return [p for p in protos
        if len(p) >= 2*k and wmint(p[-2*k:]) == ((-wort(p[-2*k])) % 3)]

"""
States & cyclic transitions:
                W       T
  L (left)      ^       v
  C (center)    ^       v
  R (right)     ^       v
"""
statevect = {'T': {'L': 'C', 'C': 'R', 'R': 'L'},
             'W': {'L': 'R', 'R': 'C', 'C': 'L'}}

def WTtoCLR(tie,startstate='L'):
    state = startstate
    ret = state
    for wt in tie:
        state = statevect[wt][state]
        ret += state
    return ret

def balance(tie):
    return len([i for i in range(1,len(tie)) if tie[i] != tie[i-1]])

def symmetry(tie,startstate='L'):
    clrtie = WTtoCLR(tie,startstate=startstate)
    return len([i for i in range(len(clrtie)) if clrtie[i]=='L']) - len([i for i in range(len(clrtie)) if clrtie[i]=='R'])


def CLRtoWT(tie):
    ret = []
    fr = tie[0]
    for st in tie[1:]:
        to = st
        if to == 'T':
            ret.append('U')
        elif statevect['W'][fr] == to:
            ret.append('W')
        elif statevect['T'][fr] == to:
            ret.append('T')
        fr = to
    return ret


def countWT(w,t):
    if w+t < 2:
        return 0
    return binom(w+t,t)-2*binom(w+t-2,t-1)


def tucks(t):
    return ktucks(t)

def ktuck(t,k):
    """
    Tests whether the end of the winding string t is a valid site for
    a k-fold tuck
    """
    if len(t) < 2*k:
        return False
    ws = [c for c in t[-2*k:] if c == 'W']
    ts = [c for c in t[-2*k:] if c == 'T']
    diff = (len(ws)-len(ts)) % 3
    if t[-2*k] == 'W':
        return diff == 2
    elif t[-2*k] == 'T':
        return diff == 1
    return False

def ktucks(t,k=1):
    """
    Annotates all valid k-fold tuck sites in a winding string
    """
    revt = list(t)
    ret = []
    while len(revt) > 0:
        if ktuck(revt,k):
            ret.insert(0,'u')
        ret.insert(0,revt.pop())
    return ret

def printall(maxN,k=1,p=lambda tt: True):
    """
    Prints out a TeX-able table of all tie knots with k-fold tuck
    sites marked. Defaults to k=1. Separated by final tuck direction.
    """
    for j,c in enumerate(['L','C','R']):
        ties = [ktucks(tt,k) for tt in prototies(wtpairs(maxN,mod3=j))
    if len(tt) > 1 and p(tt)]
        for i,t in enumerate(ties):
            print  ('%s-%d' % (c,i+1)), '&', ''.join(t), '\\\\'


finkmao = ['LRCT',
    'LRLCT',
    'LRLRCT',
    'LCRLCT',
    'LCLRCT',
    'LRLRLCT',
    'LRCLRCT',
    'LRCRLCT',
    'LCRLRCT',
    'LCLRLCT',
    'LRLRLRCT',
    'LRLCRLCT',
    'LRCLRLCT',
    'LRLCLRCT',
    'LRCRLRCT',
    'LCRLRLCT',
    'LCLRLRCT',
    'LCRCLRCT',
    'LCRCRLCT',
    'LCLCRLCT',
    'LCLCLRCT',
    'LRLRLRLCT',
    'LRLCRLRCT',
    'LRLRCLRCT',
    'LRCLRLRCT',
    'LRLRCRLCT',
    'LRCRLRLCT',
    'LCRLRLRCT',
    'LRLCLRLCT',
    'LCLRLRLCT',
    'LCRLCRLCT',
    'LCLRCLRCT',
    'LCRLCLRCT',
    'LRCLCRLCT',
    'LCLRCRLCT',
    'LRCRCLRCT',
    'LRCLCLRCT',
    'LCRCLRLCT',
    'LRCRCRLCT',
    'LCLCRLRCT',
    'LCRCRLRCT',
    'LCLCLRLCT',
    'LRLRLRLRCT',
    'LRLRCLRLCT',
    'LRLCRLRLCT',
    'LRLRLCRLCT',
    'LRCLRLRLCT',
    'LRLRCRLRCT',
    'LRLCLRLRCT',
    'LRLRLCLRCT',
    'LRCRLRLRCT',
    'LCRLRLRLCT',
    'LCLRLRLRCT',
    'LRCLRCLRCT',
    'LRCRLCRLCT',
    'LRCLRCRLCT',
    'LCRLRCLRCT',
    'LCRLCRLRCT',
    'LRCRLCLRCT',
    'LCRLRCRLCT',
    'LRLCRCLRCT',
    'LRCLCRLRCT',
    'LRLCRCRLCT',
    'LRCRCLRLCT',
    'LCLRCRLRCT',
    'LCRCLRLRCT',
    'LCRCRLRLCT',
    'LCLRLCRLCT',
    'LCLRCLRLCT',
    'LCRLCLRLCT',
    'LCLRLCLRCT',
    'LRLCLCRLCT',
    'LRCLCLRLCT',
    'LRLCLCLRCT',
    'LRCRCRLRCT',
    'LCLCRLRLCT',
    'LCLCLRLRCT',
    'LCRCLCRLCT',
    'LCLCRCLRCT',
    'LCRCRCLRCT',
    'LCRCLCLRCT',
    'LCLCRCRLCT',
    'LCRCRCRLCT',
    'LCLCLCRLCT',
    'LCLCLCLRCT']
