def antipode_ck(tree): """Return the antipode in the Butcher, Connes, Kreimer Hopf-algebra.""" # TODO: Should be memoized, but linearCOmbination is mutable. # Make LinComb clonable?? result = LinearCombination() if tree == empty_tree: result[empty_tree] = 1 return result elif isinstance(tree, Forest): result[empty_tree] = 1 for tree1, multiplicity in tree.items(): for i in range(multiplicity): tmp = LinearCombination() for forest1, multiplicity1 in antipode_ck(tree1).items(): for forest2, multiplicity2 in result.items(): tmp[forest1 * forest2] += multiplicity1 * multiplicity2 result = tmp return result # TODO: implement multiplication of LinComb. result[Forest((tree, ))] -= 1 for (forest, subtree), multiplicity in _subtrees_for_antipode(tree).items(): for forest2, coefficient in antipode_ck(forest).items(): result[forest2.add(subtree)] -= coefficient * multiplicity return result
def differentiate(thing): """performs grafting corresponding to derivate once more with respect to *t*.""" if isinstance(thing, LinearCombination): result = LinearCombination() for tree, factor in thing.items(): result += treeD(tree) * factor elif isinstance(thing, UnorderedTree): result = treeD(thing) elif thing == empty_tree: result = LinearCombination() result += leaf return result
def test_last(self): t1 = UnorderedTree([self.t3_2, self.t3_2]) result = symp_split(t1) t2 = UnorderedTree([self.t3_2, self.t2_1]) expected = LinearCombination() expected[t2] = 4 self.assertEqual(expected, result)
def test_second(self): result = subtrees(self.t2_1) expected = LinearCombination() expected[(self.et, self.t2_1)] = 1 expected[(Forest((self.t1_1, )), self.t1_1)] = 1 expected[(Forest((self.t2_1, )), self.et)] = 1 self.assertEqual(expected, result)
def linCombCommutator(op1, op2, max_order=None): """Tree commutator for linear combinations of trees.""" if isinstance(op1, UnorderedTree) or op1 == empty_tree: tmp = LinearCombination() tmp += op1 op1 = tmp if isinstance(op2, UnorderedTree) or op2 == empty_tree: tmp = LinearCombination() tmp += op2 op2 = tmp result = LinearCombination() for tree1, factor1 in op1.items(): for tree2, factor2 in op2.items(): if (not max_order) or tree1.order() + tree2.order() <= max_order: result += (factor1 * factor2) * tree_commutator(tree1, tree2) return result
def test_fourth(self): result = antipode_ck(self.t3_2) expected = LinearCombination() expected[Forest((self.t3_2, ))] = -1 expected[Forest((self.t2_1, self.t1_1))] = 2 expected[Forest((self.t1_1, self.t1_1, self.t1_1))] = -1 self.assertEqual(expected, result)
def _subtrees_for_antipode(tree): r"""Slightly modified edition of ``subtrees`` used by ``antipode_ck`` Does not include :math:`\tau \otimes \emptyset` and :math:`\emptyset \otimes \tau`. """ result = LinearCombination() tmp = [subtrees(child_tree) for child_tree in tree.elements()] # TODO: more efficient looping. if tmp: tmp = [elem.items() for elem in tmp] # TODO: Try using iterators. for item in product(*tmp): # iterator over all combinations. tensorproducts, factors = zip(*item) multiplicity = 1 for factor in factors: multiplicity *= factor cuttings, to_be_grafted = zip(*tensorproducts) with Forest().clone() as forest_of_cuttings: for forest in cuttings: forest_of_cuttings.inplace_multiset_sum(forest) result[(forest_of_cuttings, UnorderedTree(to_be_grafted))] += multiplicity result[(empty_tree, tree)] = 0 # TODO: FIND NICER WAY. return result
def test_eighth(self): result = _subtrees_for_antipode(self.t4_4) expected = LinearCombination() expected[(Forest((self.t1_1, self.t1_1, self.t1_1)), self.t1_1)] = 1 expected[(Forest((self.t1_1, self.t1_1)), self.t2_1)] = 3 expected[(Forest((self.t1_1, )), self.t3_2)] = 3 self.assertEqual(expected, result)
def series_commutator(a, b): """Corresponds to tree commutator, just for series.""" # TODO: TEST ME! def new_rule(tree): order = tree.order() if order in new_rule.orders: return new_rule.storage[tree] * tree.symmetry() # TODO: Move the correction by symmetry to initialisation. else: result = LinearCombination() for tree1, tree2 in tree_tuples_of_order(order): result += \ Fraction(a(tree1) * b(tree2), tree1.symmetry() * tree2.symmetry()) * \ tree_commutator(tree1, tree2) new_rule.orders.add(order) new_rule.storage += result return new_rule.storage[tree] * tree.symmetry() new_rule.storage = LinearCombination() new_rule.orders = set( (0, )) # the coefficient of the empty tree is always 0. return BseriesRule(new_rule)
def test_fourth(self): result = subtrees(self.t3_2) expected = LinearCombination() expected[(Forest((self.t3_2, )), self.et)] = 1 expected[(Forest((self.t1_1, self.t1_1)), self.t1_1)] = 1 expected[(Forest((self.t1_1, )), self.t2_1)] = 2 expected[(self.et, self.t3_2)] = 1 self.assertEqual(expected, result)
def test_first_second(self): tree1 = leaf tree2 = list(D(tree1).keys())[0] expected = LinearCombination() forest1 = Forest([tree1, tree1]) tree3 = UnorderedTree(forest1) expected -= tree3 result = tree_commutator(tree2, tree1) self.assertEqual(result, expected)
def test_sixth(self): result = _subtrees_for_antipode(self.t4_2) expected = LinearCombination() expected[(Forest((self.t3_2, )), self.t1_1)] = 1 expected[(Forest((self.t1_1, self.t1_1)), self.t2_1)] = 1 expected[(Forest((self.t1_1, )), self.t3_1)] = 2 print(expected) print(result) self.assertEqual(expected, result)
def subtrees(tree): """Return the HCK coproduct. This is function does the heavy lifting when composing B-series. The return value is a :class:`LinearCombination` of 2 tuples. The 0th element in the tuples are the forests of cutting, while the 1st element is the subtree. """ result = LinearCombination() if tree == empty_tree: result += (empty_tree, empty_tree) return result elif isinstance(tree, Forest): if tree.number_of_trees() == 1: for elem in tree: return subtrees(elem) else: # several trees. for elem in tree: amputated_forest = tree.sub(elem) break for pair1, multiplicity1 in subtrees(elem).items(): for pair2, multiplicity2 in subtrees(amputated_forest).items(): if isinstance(pair1[1], UnorderedTree): pair1_1 = Forest((pair1[1], )) else: pair1_1 = pair1[1] if isinstance(pair2[1], UnorderedTree): pair2_1 = Forest((pair2[1], )) else: pair2_1 = pair2[1] # TODO: Nasty workaround. pair = (pair1[0] * pair2[0], pair1_1 * pair2_1) result[pair] += multiplicity1 * multiplicity2 return result result[(Forest((tree, )), empty_tree)] = 1 if tree == leaf: result[(empty_tree, tree)] = 1 return result tmp = [subtrees(child_tree) for child_tree in tree.elements()] # TODO: more efficient looping. # TODO: The multiplicities in "tree" are accounted for by "elements()". tmp = [elem.items() for elem in tmp] # TODO: Try using iterators. for item in product(*tmp): # iterator over all combinations. tensorproducts, factors = zip(*item) multiplicity = 1 for factor in factors: multiplicity *= factor cuttings, to_be_grafted = zip(*tensorproducts) with Forest().clone() as forest_of_cuttings: for forest in cuttings: forest_of_cuttings.inplace_multiset_sum(forest) result[(forest_of_cuttings, UnorderedTree(to_be_grafted))] += \ multiplicity return result
def _split(tree): """Return the splitting of tree except for :math:`tree \otimes \emptyset`. Used by `split()`. """ result = LinearCombination() for childtree, multiplicity in tree.items(): amputated_tree = tree.sub(childtree) result[(childtree, amputated_tree)] = multiplicity childSplits = _split(childtree) for pair, multiplicity2 in childSplits.items(): new_tree = amputated_tree.add(pair[1]) new_pair = (pair[0], new_tree) result[new_pair] = multiplicity * multiplicity2 return result
def new_rule(tree): order = tree.order() if order in new_rule.orders: return new_rule.storage[tree] * tree.symmetry() # TODO: Move the correction by symmetry to initialisation. else: result = LinearCombination() for tree1, tree2 in tree_tuples_of_order(order): result += \ Fraction(a(tree1) * b(tree2), tree1.symmetry() * tree2.symmetry()) * \ tree_commutator(tree1, tree2) new_rule.orders.add(order) new_rule.storage += result return new_rule.storage[tree] * tree.symmetry()
def graft(other, base): r"""Grafting *other* :math:`\curvearrowright` *base*.""" result = LinearCombination() if base == empty_tree: result += other elif other == empty_tree: result += base else: result += base.butcher_product(other) for subtree, multiplicity1 in base.items(): amputated_tree = base.sub(subtree) replacements = graft(other, subtree) for replacement, multiplicity2 in replacements.items(): new_tree = amputated_tree.add(replacement) result[new_tree] += multiplicity1 * multiplicity2 return result
def symp_split(tree): """Perform the split needed for symplecticity checks. It differs from the ``split``-function by only splitting off leaves.""" result = LinearCombination() for childtree, multiplicity in tree.items(): amputated_tree = tree.sub(childtree) if childtree == leaf: result[amputated_tree] += multiplicity else: child_splits = symp_split(childtree) for tree2, multiplicity2 in child_splits.items(): new_tree = amputated_tree.add(tree2) result[new_tree] += multiplicity * multiplicity2 return result
def test_thirteenth(self): result = symp_split(self.t5_5) expected = LinearCombination() expected[self.t4_1] = 1 expected[self.t4_3] = 1 self.assertEqual(expected, result)
def test_first(self): result = antipode_ck(self.t1_1) expected = LinearCombination() expected[Forest((leaf, ))] = -1 self.assertEqual(expected, result)
def test_first(self): result = symp_split(self.t1_1) expected = LinearCombination() # TODO: right way to do it? self.assertEqual(expected, result)
def test_second(self): result = antipode_ck(self.t2_1) expected = LinearCombination() expected[Forest((self.t2_1, ))] = -1 expected[Forest((self.t1_1, self.t1_1))] = 1 self.assertEqual(expected, result)
def test_fourth(self): result = symp_split(self.t3_2) expected = LinearCombination() expected[self.t2_1] = 2 self.assertEqual(expected, result)
def test_second(self): result = symp_split(self.t2_1) expected = LinearCombination() expected += self.t1_1 self.assertEqual(expected, result)
def test_tenth(self): result = symp_split(self.t5_2) expected = LinearCombination() expected[self.t4_1] = 2 self.assertEqual(expected, result)
def test_fifth(self): result = symp_split(self.t4_1) expected = LinearCombination() expected[self.t3_1] = 1 self.assertEqual(expected, result)
def test_eleventh(self): result = symp_split(self.t5_3) expected = LinearCombination() expected[self.t4_1] = 1 expected[self.t4_2] = 1 self.assertEqual(expected, result)
def test_empty(self): result = subtrees(self.et) expected = LinearCombination() expected[(self.et, self.et)] = 1 self.assertEqual(expected, result)
def test_twelfth(self): result = symp_split(self.t5_4) expected = LinearCombination() expected[self.t4_2] = 3 self.assertEqual(expected, result)
def test_seventeenth(self): result = symp_split(self.t5_9) expected = LinearCombination() expected[self.t4_4] = 4 self.assertEqual(expected, result)
def test_sixthteenth(self): result = symp_split(self.t5_8) expected = LinearCombination() expected[self.t4_4] = 1 expected[self.t4_3] = 2 self.assertEqual(expected, result)