This is because symbols in sympy only match if they have the same assumptions:
In [23]: (x, y, z), = diophantine(x + y + z, t)
In [24]: x
Out[24]: t₀
In [25]: type(x)
Out[25]: sympy.core.symbol.Symbol
In [26]:
x.name
Out[26]: 't_0'
In [28]: x.assumptions0
Out[28]:
{'integer': True,
'complex': True,
'commutative': True,
'rational': True,
'algebraic': True,
'extended_real': True,
'imaginary': False,
'real': True,
'irrational': False,
'hermitian': True,
'finite': True,
'infinite': False,
'transcendental': False,
'noninteger': False}
In [29]: x == Symbol('t_0')
Out[29]: False
In [30]: x == Symbol('t_0', integer=True)
Out[30]: True
If we use integer=True then the substitution will work:
In [31]: t_0, t_1 = symbols('t_0, t_1', integer=True)
In [32]: tuple(s.subs({t_0:0, t_1:0}) for s in (x, y, z))
Out[32]: (0, 0, 0)
Note that this kind of situation was discussed in a recent thread and
you can use free symbols:
In [1]: sol, = diophantine(x + y + z, t)
In [2]: sol
Out[2]: (t₀, t₁, -t₀ - t₁)
In [3]: syms = Tuple(*sol).free_symbols
In [4]: rep = {s: 0 for s in syms}
In [5]: tuple(s.subs(rep) for s in sol)
Out[5]: (0, 0, 0)
Personally I think it's a poor API that inserts new symbols without
also returning the list of those symbols and it would be better if it
was like:
(sol, params), = diophantine(x + y + z, t)
Here params would directly return (t_0, t_1) for further use.
Alternatively it should be possible to provide the symbols directly:
sol, = diophantine(x + y + z, [t_0, t_1])
Oscar