Not perfect... but helpful.
A time ago I was trying something related to your question. After a while of looking on the web (and asking... just like you!) I came out with the following: define a circular function.
Let $a$ and $b$ be noncommuting, but distributable
I define the function
def isCircular(arr1, arr2):
return arr1 in arr2+' '+arr2
and a expression to test
expr := (a + b)**2;
The trick is now to convert this to a string, split it, and compare term by term if they are circular. NOTE: blank spaces before and after the plus sign inside the
list = str(expr)
list = str(expr).split(' + ')
for i in range(len(list)):
for j in range(i+1,len(list)):
if isCircular( list[i], list[j]):
list[j] = list[i]
Then, convert it back to a cadabra expression to finally simplify. NOTE: the
newexpr is initalised as an empty expression, it is not a single double quote, but double single quotes.
newexpr = '';
for word in list:
newexpr = newexpr + ' + ' + word
cab_expr = Ex(newexpr)
I tried something like
expr := (a b + b a)**2; and the result is almost there! It could be a starting point!!!