def test_pi1_pi1adjoint(): lc_1 = parse_concatenation('12-21') assert pi1(lc_1, 2) == lc_1 lc_1 = parse_concatenation('12') assert pi1(lc_1, 2) == pi1(pi1(lc_1, 2), 2) lc_1 = parse_concatenation('123') lc.assert_almost_equal(pi1(lc_1, 3), pi1(pi1(lc_1, 3), 3)) dim = 2 n = 3 for w in itertools.product(range(1, dim + 1), repeat=n): left = lc.lift(ShuffleWord(w)) for v in itertools.product(range(1, dim + 1), repeat=n): right = lc.lift(ConcatenationWord(v)) assert inner_product_sw_cw(left, pi1(right, n)) == inner_product_sw_cw( pi1adjoint(left, n), right) # pi1adjoint does _not_ depend on the realization of an element in the dual of Lie inside of T(\R^d). assert pi1adjoint(parse_shuffle('12'), 2) == pi1adjoint(parse_shuffle('[0.5] 12 - [0.5] 21'), 2) # For everything orthogonal on Lie, the result should be zero. zero = lc.LinearCombination() assert pi1adjoint(parse_shuffle('11'), 2) == zero assert pi1adjoint(parse_shuffle('22'), 2) == zero lc.assert_almost_equal( pi1adjoint(parse_shuffle('12') * parse_shuffle('21'), 4), zero)
def permutation_invariants(dim,level): """Basis for the permutation invariants.""" partitions = set_partitions( range(level), dim ) invs = [] for p in partitions: inv = dict() for draw in possible_draws_without_repetition( range(1,dim+1), len(p) ): inv[ words.ShuffleWord(_partition_draw_to_word(level,p,draw)) ] = 1 invs.append(lc.LinearCombination(inv)) return invs
def test_shuffle_word(): t = lambda x, y: lc.Tensor((x, y)) def sw(*args): return ShuffleWord(args) lc_1 = lc.lift(sw(1, 2)) lc_2 = lc.lift(sw(3, )) assert lc.LinearCombination( {sw( 1,2,3 ):1, sw( 1,3,2 ):1, sw( 3,1,2 ):1} ) \ == lc_1 * lc_2 assert lc.LinearCombination( {t( sw(), sw(1,2) ):1, t(sw(1),sw(2)):1, t( sw(1,2), sw() ):1} ) \ == lc_1.apply_linear_function( ShuffleWord.coproduct ) # Condition on product vs coproduct: \Delta( \tau \tau' ) = \Delta(\tau) \Delta(\tau'). lc_1 = lc.lift(sw(1, 2)) lc_2 = lc.lift(sw()) assert (lc_1 * lc_2).apply_linear_function( ShuffleWord.coproduct ) \ == lc_1.apply_linear_function( ShuffleWord.coproduct ) \ * lc_2.apply_linear_function( ShuffleWord.coproduct ) lc_1 = lc.lift(sw(1, 2)) lc_2 = lc.lift(sw(3, )) assert (lc_1 * lc_2).apply_linear_function( ShuffleWord.coproduct ) \ == lc_1.apply_linear_function( ShuffleWord.coproduct ) \ * lc_2.apply_linear_function( ShuffleWord.coproduct ) # Condition on antipode: \Nabla (A \otimes id) \Delta = \eta \vareps. assert lc.LinearCombination() \ == lc_1.apply_linear_function(ShuffleWord.coproduct)\ .apply_linear_function( lc.Tensor.fn_otimes_linear(lc.id,ShuffleWord.antipode) )\ .apply_linear_function( lc.Tensor.m12 ) assert lc.lift(sw()) \ == lc.lift(sw())\ .apply_linear_function(ShuffleWord.coproduct)\ .apply_linear_function( lc.Tensor.fn_otimes_linear(lc.id,ShuffleWord.antipode) )\ .apply_linear_function( lc.Tensor.m12 ) # Unit. assert lc_1 == ShuffleWord.unit() * lc_1 # Counit. assert lc_1 == lc_1\ .apply_linear_function( ShuffleWord.coproduct )\ .apply_linear_function( lc.Tensor.id_otimes_fn( ShuffleWord.counit) )
def restricted_permutation_invariants_for_partition(dim,level,p): """Put 1 in the first box; fill other boxes; permute all.""" for draw in possible_draws_without_repetition( range(2,dim+1), len(p)-1 ): #inv = fla.Elt([]) # XXX inv = lc.LinearCombination() draw = [1] + draw word = _partition_draw_to_word( level, p, draw ) for perm in restricted_permutations( dim ): permuted = map( lambda n: ((word[n]-1)^perm) +1, range(level) ) # XXX signature / words .. is 1-based but permutations are 0-based inv += lc.LinearCombination.lift( words.ShuffleWord(permuted) ) # XXX slow #fla.word2Elt( tuple(permuted) ) yield inv
def _gl_invariant_for_identity(dim,level): assert level % dim == 0 weight = level // dim result = dict() for taus in itertools.product(symmetric(dim),repeat=weight): index = [] sign = 1 for tau in taus: sign *= tau.signature() for i in range(dim): index.append( (i^tau) + 1) result[ words.ShuffleWord(index) ] = sign return lc.LinearCombination(result)
def _so_invariants_without_det(dim,level): if level % 2 == 1: yield from [] else: for partitions in equal_size_partitions(range(0,level), 2): inv = defaultdict(int) for letters in itertools.product( range(1,dim+1), repeat=level//2 ): current_word = np.zeros( level, dtype=np.int8 ) for i in range(level//2): current_word[ partitions[i][0] ] = letters[i] current_word[ partitions[i][1] ] = letters[i] inv[ words.ShuffleWord(current_word) ] += 1 yield lc.LinearCombination(inv)
def hoffman_LOG_dual(psi): """p.58 in Hoffman""" # XXX Slow hack. def _LOG_dual_monomial(m): _ret = lc.LinearCombination() for C in finer(CompositionConcatenation((m, ))): _ret += sympy.Rational((-1)**(len(C) - 1), len(C)) * lc.lift(C) return _ret ret = lc.LinearCombination() for D, c in psi.items(): ret += c * reduce(operator.mul, map(_LOG_dual_monomial, D)) return ret
def gl_invariants(dim,level): """Basis for the GL invariants.""" if level % dim != 0: return else: weight = level // dim for_identity = _gl_invariant_for_identity(dim,level) for yt in rectangular_standard_young_tableaux(dim, weight): sigma = _tableau_to_permutation( yt )**(-1) def permute(word): letters = word permuted = tuple( letters[i^sigma] for i in range(len(letters)) ) return words.ShuffleWord(permuted) yield lc.LinearCombination( {permute(x):y for x,y in for_identity.items()} )
def signature(x, upto_level): # TODO Using Chen might be faster. ONE = dp.CompositionConcatenation() if isinstance(x, list) or isinstance(x, tuple): x = np.array(x) if len(x.shape) == 1: x = x[np.newaxis, :] dim, N = x.shape delta_x = np.diff(x, prepend=0, axis=1) prevz = [ONE] sig = lc.LinearCombination({ONE: np.ones(N)}) for level in range(1, upto_level + 1): currentz = [] for ell in range(0, dim): for prev in prevz: if not prev == ONE: concat_v = dp.CompositionConcatenation( tuple(p for p in prev) + (dp.Monomial({ell: 1}), )) concat_s = np.hstack( (np.array([0.]), np.cumsum(sig[prev][0:-1] * delta_x[ell][1:]))) currentz.append(concat_v) sig[concat_v] = concat_s if prev == ONE: last_monomial = dp.Monomial() else: last_monomial = dp.Monomial(prev[-1]) dp.safe_add(last_monomial, ell, +1) bullet_v = dp.CompositionConcatenation( tuple(p for p in prev[0:-1]) + (last_monomial, )) bullet_s = np.hstack( (np.array([0.]), np.cumsum(sig[prev][1:] * delta_x[ell][1:]))) if not prev == ONE: bullet_s = bullet_s - concat_s currentz.append(bullet_v) sig[bullet_v] = bullet_s prevz = currentz return sig
def _so_invariants_with_one_det(dim,level): # no determinant fits or, using one determinant, the other spots cannot be used for inner products if level < dim or (level - dim) % 2 == 1: yield from [] elif level == dim: yield _gl_invariant_for_identity(dim, dim) else: for det_positions in itertools.combinations(range(level),dim): # positions for the determinant rest = set(range(level))-set(det_positions) for partitions in equal_size_partitions(rest, 2): inv = defaultdict(int) for tau in symmetric(dim): for letters in itertools.product( range(1,dim+1), repeat=level//2 ): current_word = np.zeros( level, dtype=np.int8 ) for i in range( (level-dim)//2 ): current_word[ partitions[i][0] ] = letters[i] current_word[ partitions[i][1] ] = letters[i] det_letters = [ (i^tau) + 1 for i in range(dim) ] for i in range(dim): current_word[ det_positions[i] ] = det_letters[i] sign = tau.signature() inv[ words.ShuffleWord(current_word) ] += sign yield lc.LinearCombination( inv )
def test_lead_lag(): ################# # Map to lead-lag. ################# def replace_multidim(m, _dim): # [0,1,2] # [0',0'',1',1'',2',2''] if len(m) == 0: fail types = [] tmp = {} for d in range(2 * _dim): if m.get(d, 0) >= 1: go_to = d // 2 if d % 2 == 0: typ = 'left' else: typ = 'right' types.append(typ) tmp[go_to] = m[d] if all(map(lambda s: s == 'left', types)) or all( map(lambda s: s == 'right', types)): return types[0], dp.Monomial(tmp) else: return None, None def _ll_to_ds_multidim(_dim): def __ll_to_ds_multidim(cqs): if len(cqs) == 1: t, rep = replace_multidim(cqs[0], _dim) if not rep is None: yield (dp.CompositionQuasiShuffle( (dp.Monomial(rep), )), +1) else: last = cqs[-1] t_last, rep_last = replace_multidim(last, _dim) if rep_last == None: return second_to_last = cqs[-2] t_second_to_last, rep_second_to_last = replace_multidim( second_to_last, _dim) if rep_second_to_last == None: return for x, c in __ll_to_ds_multidim(cqs[0:-1]): yield (dp.CompositionQuasiShuffle(x + (rep_last, )), +1) if t_second_to_last == 'left' and t_last == 'right': merged = dp.Monomial(x[-1]) for _x, _p in rep_last.items(): dp.safe_add(merged, _x, _p) yield (dp.CompositionQuasiShuffle(x[:-1] + (merged, )), +1) return __ll_to_ds_multidim def ll_to_ds_multidim(phi, _dim): return phi.apply_linear_function(_ll_to_ds_multidim(_dim)) z = np.random.randint(-100, 100, size=(2, 10)) doubles = [] for d in range(2): double = [] for i in range(0, len(z[d])): double.append(z[d, i]) double.append(z[d, i]) doubles.append(double) xs = [] for d in range(2): xs.append(doubles[d][1:]) xs.append(doubles[d][:-1]) x = np.vstack(xs) DSx = iss.terminal_values(iss.signature(x, 4)) DSz = iss.terminal_values(iss.signature(z, 4)) # 1' \mapsto 1 assert get(M_qs({0: 1}), DSx) == get(M_qs({0: 1}), DSz) assert ll_to_ds_multidim(M_qs({0: 1}), 2) == M_qs({0: 1}) # 1'' \mapsto 1 assert get(M_qs({1: 1}), DSx) == get(M_qs({0: 1}), DSz) assert ll_to_ds_multidim(M_qs({1: 1}), 2) == M_qs({0: 1}) # [1'^2] \mapsto (1^2) assert get(M_qs({0: 2}), DSx) == get(M_qs({0: 2}), DSz) assert ll_to_ds_multidim(M_qs({0: 2}), 2) == M_qs({0: 2}) # [1''^2] \mapsto (1^2) assert get(M_qs({1: 2}), DSx) == get(M_qs({0: 2}), DSz) assert ll_to_ds_multidim(M_qs({1: 2}), 2) == M_qs({0: 2}) # [1'1''] \mapsto _ assert get(M_qs({0: 1, 1: 1}), DSx) == 0 assert ll_to_ds_multidim(M_qs({0: 1, 1: 1}), 2) == lc.LinearCombination() # 1'1' \mapsto 11 assert get(M_qs({0: 1}, {0: 1}), DSx) == get(M_qs({0: 1}, {0: 1}), DSz) assert ll_to_ds_multidim(M_qs({0: 1}, {0: 1}), 2) == M_qs({0: 1}, {0: 1}) # 1'1'' \mapsto 11 + [1^2] assert get(M_qs({0: 1}, {1: 1}), DSx) == get(M_qs({0: 1}, {0: 1}), DSz) + get(M_qs({0: 2}), DSz) assert ll_to_ds_multidim(M_qs({0: 1}, {1: 1}), 2) == M_qs({0: 1}, {0: 1}) + M_qs({0: 2}) # 1''1' \mapsto 11 assert get(M_qs({1: 1}, {0: 1}), DSx) == get(M_qs({0: 1}, {0: 1}), DSz) assert ll_to_ds_multidim(M_qs({1: 1}, {0: 1}), 2) == M_qs({0: 1}, {0: 1}) # 1'1''1' \mapsto 111 + (1^2)1 assert get(M_qs({0: 1}, {1: 1}, {0: 1}), DSx) == get( M_qs({0: 1}, {0: 1}, {0: 1}), DSz) + get(M_qs({0: 2}, {0: 1}), DSz) assert ll_to_ds_multidim( M_qs({0: 1}, {1: 1}, {0: 1}), 2) == M_qs({0: 1}, {0: 1}, {0: 1}) + M_qs({0: 2}, {0: 1}) # 1''1'1'' \mapsto 111 + 1(1^2) assert get(M_qs({1: 1}, {0: 1}, {1: 1}), DSx) == get( M_qs({0: 1}, {0: 1}, {0: 1}), DSz) + get(M_qs({0: 1}, {0: 2}), DSz) assert ll_to_ds_multidim( M_qs({1: 1}, {0: 1}, {1: 1}), 2) == M_qs({0: 1}, {0: 1}, {0: 1}) + M_qs({0: 1}, {0: 2}) # 1''[1'^2] \mapsto 1[1^2] assert get(M_qs({1: 1}, {0: 2}), DSx) == get(M_qs({0: 1}, {0: 2}), DSz) assert ll_to_ds_multidim(M_qs({1: 1}, {0: 2}), 2) == M_qs({0: 1}, {0: 2}) # 1'[1''^2] \mapsto 1[1^2] + [1^3] assert get( M_qs({0: 1}, {1: 2}), DSx) == get(M_qs({0: 1}, {0: 2}), DSz) + +get(M_qs({0: 3}), DSz) assert ll_to_ds_multidim(M_qs({0: 1}, {1: 2}), 2) == M_qs({0: 1}, {0: 2}) + M_qs({0: 3}) # It does the job. for C1 in dp.compositions(range(4), 4): phi = M_qs(*C1) assert get(ll_to_ds_multidim(phi, 2), DSz) == get(phi, DSx) # It is a quasi-shuffle morphism. assert ll_to_ds_multidim(M_qs({0: 1}, {1: 1}), 2) * ll_to_ds_multidim( M_qs({2: 1}, {3: 1}), 2) == ll_to_ds_multidim( M_qs({0: 1}, {1: 1}) * M_qs({2: 1}, {3: 1}), 2) assert ll_to_ds_multidim(M_qs({0: 1}, {1: 1}), 2) * ll_to_ds_multidim( M_qs({2: 1}, {2: 1}), 2) == ll_to_ds_multidim( M_qs({0: 1}, {1: 1}) * M_qs({2: 1}, {2: 1}), 2) assert ll_to_ds_multidim(M_qs({0: 1}, {1: 1}), 2) * ll_to_ds_multidim( M_qs({3: 1}, {3: 1}), 2) == ll_to_ds_multidim( M_qs({0: 1}, {1: 1}) * M_qs({3: 1}, {3: 1}), 2) assert ll_to_ds_multidim(M_qs({0: 1}, {0: 1}), 2) * ll_to_ds_multidim( M_qs({2: 1}, {2: 1}), 2) == ll_to_ds_multidim( M_qs({0: 1}, {0: 1}) * M_qs({2: 1}, {2: 1}), 2) comps = list(dp.compositions(range(4), 3)) for i in range(len(comps)): for j in range(i + 1): C1 = comps[i] C2 = comps[j] phi = M_qs(*C1) psi = M_qs(*C2) assert ll_to_ds_multidim( phi * psi, 2) == ll_to_ds_multidim(phi, 2) * ll_to_ds_multidim(psi, 2)
def _LOG_dual_monomial(m): _ret = lc.LinearCombination() for C in finer(CompositionConcatenation((m, ))): _ret += sympy.Rational((-1)**(len(C) - 1), len(C)) * lc.lift(C) return _ret
def _EXP_dual_monomial(m): _ret = lc.LinearCombination() for C in finer(CompositionConcatenation((m, ))): _ret += sympy.Rational(1, sympy.factorial(len(C))) * lc.lift(C) return _ret
def test_concatentation_word(): def lcw(*args): return lc.lift(ConcatenationWord(args)) assert lcw(1, 2, 3) + 77 * lcw(1, 9) == lc.LinearCombination.from_str( "123 + [77] 19", ConcatenationWord) t = lambda x, y: lc.Tensor((x, y)) def cw(*args): return ConcatenationWord(args) lc_1 = lc.lift(cw(1, 2)) lc_2 = lc.lift(cw(3)) assert lc.LinearCombination({ConcatenationWord((1, 2, 3)): 1}) == lc_1 * lc_2 o = lc.LinearCombination.otimes(lc_1, lc_1 + 7 * lc_2) assert lc.LinearCombination( { t(cw(1,2,1,2), cw(1,2,1,2)):1, t(cw(1,2,1,2),cw(1,2,3)):7, t(cw(1,2,1,2),cw(3,1,2)):7, t(cw(1,2,1,2),cw(3,3)):49} )\ == o * o lc_1 = lc.lift(cw(1, 2)) lc_2 = lc.lift(cw(3, 4, 5)) def id_otimes_coproduct(t): for x, c in ConcatenationWord.coproduct(t[1]): yield (lc.Tensor((t[0], x[0], x[1])), c) def coproduct_otimes_id(t): for x, c in ConcatenationWord.coproduct(t[0]): yield (lc.Tensor((x[0], x[1], t[1])), c) # Coassociativity. assert lc_1.apply_linear_function( ConcatenationWord.coproduct ).apply_linear_function( lc.Tensor.fn_otimes_linear( lc.id, ConcatenationWord.coproduct ) ) \ == lc_1.apply_linear_function( ConcatenationWord.coproduct ).apply_linear_function( lc.Tensor.fn_otimes_linear( ConcatenationWord.coproduct, lc.id ) ) assert lc_2.apply_linear_function( ConcatenationWord.coproduct ).apply_linear_function( lc.Tensor.fn_otimes_linear( lc.id, ConcatenationWord.coproduct ) ) \ == lc_2.apply_linear_function( ConcatenationWord.coproduct ).apply_linear_function( lc.Tensor.fn_otimes_linear( ConcatenationWord.coproduct, lc.id ) ) # Condition on product vs coproduct: \Delta( \tau \tau' ) = \Delta(\tau) \Delta(\tau'). assert (lc_1 * lc_2).apply_linear_function( ConcatenationWord.coproduct ) \ == lc_1.apply_linear_function( ConcatenationWord.coproduct ) \ * lc_2.apply_linear_function( ConcatenationWord.coproduct ) # Condition on antipode: \Nabla (A \otimes id) \Delta = \eta \vareps. assert lc.LinearCombination() \ == lc_1.apply_linear_function(ConcatenationWord.coproduct)\ .apply_linear_function( lc.Tensor.fn_otimes_linear(lc.id,ConcatenationWord.antipode) )\ .apply_linear_function( lc.Tensor.m12 ) assert lc.lift(cw()) \ == lc.lift(cw())\ .apply_linear_function(ConcatenationWord.coproduct)\ .apply_linear_function( lc.Tensor.fn_otimes_linear(lc.id,ConcatenationWord.antipode) )\ .apply_linear_function( lc.Tensor.m12 ) # Unit. assert lc_1 == ConcatenationWord.unit() * lc_1 # Counit. #assert lc_1 == lc_1.apply_linear_function( ConcatenationWord.coproduct )\ # .apply_linear_function( lc.Tensor.fn_otimes_linear( lc.id, ConcatenationWord.counit ) )\ # .apply_linear_function( lc.Tensor.projection(0) ) assert lc_1 == lc_1.apply_linear_function( ConcatenationWord.coproduct )\ .apply_linear_function( lc.Tensor.id_otimes_fn( ConcatenationWord.counit ) ) # The inner product is a bit awkward: # The natural dual of the concatenation algebra is the shuffle algebra. # But the method LinearCombination.inner_product only works with vectors of the exact same type. # Hence we need to transform one of them into the other. assert 1 == lc.LinearCombination.inner_product(lc_1, lc_1) lc_sw_1 = lc.lift(ShuffleWord((1, 2))) assert 0 == lc.LinearCombination.inner_product(lc_sw_1, lc_1) assert 1 == lc.LinearCombination.inner_product( lc_sw_1.apply_linear_function(shuffle_word_to_concatenation_word), lc_1)
def terminal_values(s): return lc.LinearCombination({v: c[-1] for v, c in s.items()})