The bug is not so much that distribution does not happen automatically (more on that below), but that the last term is manifestly wrong (there should be no A ^ B
in the answer). I don't know how that slipped the net, but it's embarrassing... Will fix.
Now the distribution thing. In Cadabra, distribution of operators over sums is not automatic, you need to call
distribute(ge);
explicitly to make that happen. Similarly, the product rule is not applied automatically; you need to call
product_rule(ge);
explicitly. If you do want this to happen automatically, define your post_process
function to read something like
def post_process(ex):
distribute(ex)
sort_product(ex)
collect_terms(ex)
(you can stick this in the first cell of the notebook).