Firstly commutative=False applies only to multiplication and not addition so it has no effect here.
There are several different orderings to be aware of. One is the internal order of the terms in an Add
. The other is the order in which terms are displayed which is not necessarily the same:
In [35]: e = sum(fdict.keys())
In [36]: e
Out[36]: x⋅y + x + y
In [37]: e.args
Out[37]: (x, y, x⋅y)
In [38]: str(e)
Out[38]: 'x*y + x + y'
In [39]: print(e)
x*y + x + y
Depending on what you are doing you might only care about one of these or you might care about both.
To keep the internal order unchanged you can use Add
with evaluate=False
:
In [43]: list(fdict)
Out[43]: [y, x, x⋅y]
In [44]: e2 = Add(*fdict, evaluate=False)
In [45]: e2.args
Out[45]: (y, x, x⋅y)
In [46]: e2
Out[46]: x⋅y + x + y
You can see that Add with evaluate=False preserves the order of fdict
. However the expression still does not display in that order. You can change the display order to respect the internal ordering:
In [47]: init_printing(order='none')
In [48]: e2
Out[48]: y + x + x⋅y
Of course the above all presumes that your f
had the correct order in the first place but for that you need to use Add
again:
In [50]: init_printing(order='none')
In [51]: f = Add(3*x, 2*y, x*y, evaluate=False)
In [52]: f
Out[52]: 3⋅x + 2⋅y + x⋅y
In [53]: fdict = f.as_coefficients_dict()
In [54]: print(fdict)
defaultdict(<class 'int'>, {x: 3, y: 2, x*y: 1})
In [55]: e3 = Add(*fdict, evaluate=False)
In [56]: e3
Out[56]: x + y + x⋅y
Lastly the ordering of dictionaries is something that is controllable in recent versions of Python but in previous versions the ordering of a dict
was always unpredictable. SymPy has existed long before dictionary order was meaningful so you should understand that any function/method like as_coefficients_dict
which returns a dict
is something that was by design not expected to return items in any well-defined order. You should not presume that any random function that happens to return a dict will give any guarantee about the ordering of the keys in that dict unless there is some documentation to that effect.