Kwant discretizer fails when expression includes sqrt(parameter)
This code
import kwant.continuum
ham = "sqrt(1 - B_x) * kron(sigma_0, sigma_x)"
kwant.continuum.discretizer.discretize(ham, coords=['x'])
fails with the following traceback
TypeError Traceback (most recent call last)
<ipython-input-4-c24dd4d4768b> in <module>
1 import kwant.continuum
2 ham = "sqrt(1 - B_x) * kron(sigma_0, sigma_x)"
----> 3 kwant.continuum.discretizer.discretize(ham, coords=['x'])
/opt/conda/lib/python3.8/site-packages/kwant/continuum/discretizer.py in discretize(hamiltonian, coords, grid, locals, grid_spacing)
140 """
141 tb, coords = discretize_symbolic(hamiltonian, coords, locals=locals)
--> 142 return build_discretized(tb, coords, grid=grid, grid_spacing=grid_spacing)
143
144
/opt/conda/lib/python3.8/site-packages/kwant/continuum/discretizer.py in build_discretized(tb_hamiltonian, coords, grid, locals, grid_spacing)
348 name = 'hopping_{}'.format(n)
349
--> 350 tb[offset] = _builder_value(hopping, coords, np.diag(lat.prim_vecs),
351 onsite, name)
352
/opt/conda/lib/python3.8/site-packages/kwant/continuum/discretizer.py in _builder_value(expr, coords, grid_spacing, onsite, name)
643 expr = expr.subs({_displacements[c]: grid_spacing[n]
644 for n, c in enumerate(coords)})
--> 645 return_string, map_func_calls, const_symbols, _cache = _return_string(
646 expr, coords=coords)
647
/opt/conda/lib/python3.8/site-packages/kwant/continuum/discretizer.py in _return_string(expr, coords)
579 # which will be assigned to '_cache_n' in the function body.
580 mons = monomials(expr, expr.atoms(sympy.Symbol))
--> 581 mons = {k: cache(v) for k, v in mons.items()}
582 mons = ["{} * {}".format(_print_sympy(k), _print_sympy(v))
583 for k, v in mons.items()]
/opt/conda/lib/python3.8/site-packages/kwant/continuum/discretizer.py in <dictcomp>(.0)
579 # which will be assigned to '_cache_n' in the function body.
580 mons = monomials(expr, expr.atoms(sympy.Symbol))
--> 581 mons = {k: cache(v) for k, v in mons.items()}
582 mons = ["{} * {}".format(_print_sympy(k), _print_sympy(v))
583 for k, v in mons.items()]
/opt/conda/lib/python3.8/site-packages/kwant/continuum/discretizer.py in cache(x)
559 def cache(x):
560 s = sympy.symbols('_cache_{}'.format(len(_cache)))
--> 561 _cache[str(s)] = ta.array(x.tolist(), complex)
562 return s
563
/opt/conda/lib/python3.8/site-packages/sympy/core/expr.py in __complex__(self)
330 result = self.evalf()
331 re, im = result.as_real_imag()
--> 332 return complex(float(re), float(im))
333
334 def _cmp(self, other, op, cls):
/opt/conda/lib/python3.8/site-packages/sympy/core/expr.py in __float__(self)
325 if result.is_number and result.as_real_imag()[1]:
326 raise TypeError("can't convert complex to float")
--> 327 raise TypeError("can't convert expression to float")
328
329 def __complex__(self):
TypeError: can't convert expression to float
The same piece of code works if I replace the sqrt
with other functions such as sin
, cos
, etc.
Part of the problem seems to be that square roots are not caught by this segment in kwant.continuum.discretizer._return_string:
map_func_calls = expr.atoms(AppliedUndef, sympy.Function)
map_func_calls = {s: sympy.symbols('_const_{}'.format(n))
for n, s in enumerate(map_func_calls)}
That's because square roots in sympy are sympy.Pow
objects and not sympy.Function
:
isinstance(sympy.sqrt(1-sympy.Symbol('B_x')), sympy.Function)
>>> False
However, just adding sympy.Pow
to the expr.atoms
call doesn't solve the problem.