brian2.units do not work with python’s complex numbers. As currently brian2
integrators do not support complex numbers this may not seem like a problem at all. However, if one continues to work with brian2 units also in analytical and symbolic parts of ones code, e.g., comparing spike spectra from Brian simmulations to some theory, one ends up with complex expressions. In these cases it would be great if one can just use the same units system.
One solution to this might be to undertand if brian2’s units were derived and are compatible to some other python unit system, and then see if some of them are complex number compatible.
Cheers and stay healthy!
ttxtea
1 Like
Hi. Never thought about this much, I wonder whether in practice it would be that useful in practice, given that complex signal processing functions etc. would probably not correctly deal with the units internally. Do you have any concrete example we could discuss?
On a basic level, using the unit system with complex numbers should already work:
>>> x = (np.arange(3) + 1j)*mV + (4 + 2j)*mV
>>> x
array([4.+3.j, 5.+3.j, 6.+3.j]) * mvolt
>>> np.abs(x)
array([5. , 5.83095189, 6.70820393]) * mvolt
>>> np.mean(x)
5.+3.j * mvolt
Wow, this means basic complex number functionality it is already implemented. I am sorry to not have noticed that. When I do
import brian2
brian2.Hz * 1j
in atom/hydrogen
. It results in
`---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~/.local/lib/python3.8/site-packages/IPython/core/formatters.py in __call__(self, obj)
343 method = get_real_method(obj, self.print_method)
344 if method is not None:
--> 345 return method()
346 return None
347 else:
~/.local/lib/python3.8/site-packages/brian2/units/fundamentalunits.py in _repr_latex_(self)
1605
1606 def _repr_latex_(self):
-> 1607 return '`
```
0.+1.j * hertz
``` + latex(self) + '`
```
DISCOURSE_PLACEHOLDER_2
```
1608
1609 def __str__(self):
~/.local/lib/python3.8/site-packages/sympy/printing/printer.py in __call__(self, *args, **kwargs)
371
372 def __call__(self, *args, **kwargs):
--> 373 return self.__wrapped__(*args, **kwargs)
374
375 @property
~/.local/lib/python3.8/site-packages/sympy/printing/latex.py in latex(expr, **settings)
2913
2914 """
-> 2915 return LatexPrinter(settings).doprint(expr)
2916
2917
~/.local/lib/python3.8/site-packages/sympy/printing/latex.py in doprint(self, expr)
252
253 def doprint(self, expr):
--> 254 tex = Printer.doprint(self, expr)
255
256 if self._settings['mode'] == 'plain':
~/.local/lib/python3.8/site-packages/sympy/printing/printer.py in doprint(self, expr)
289 def doprint(self, expr):
290 """Returns printer's representation for expr (as a string)"""
--> 291 return self._str(self._print(expr))
292
293 def _print(self, expr, **kwargs):
~/.local/lib/python3.8/site-packages/sympy/printing/printer.py in _print(self, expr, **kwargs)
306 if (self.printmethod and hasattr(expr, self.printmethod)
307 and not isinstance(expr, BasicMeta)):
--> 308 return getattr(expr, self.printmethod)(self, **kwargs)
309
310 # See if the class of expr is known, or if one of its super
~/.local/lib/python3.8/site-packages/brian2/units/fundamentalunits.py in _latex(self, expr)
1599 unitless = np.array(self / best_unit, copy=False)
1600 if unitless.ndim == 0:
-> 1601 sympy_quantity = np.float(unitless)
1602 else:
1603 sympy_quantity = Matrix(unitless)
TypeError: can't convert complex to float`
```
DISCOURSE_PLACEHOLDER_2
```
However, the same expression in normal ipython
console works as you have suggested. This must be some issues concerning my installation. So sorry again for presuming complex numbers would not work in general. I’ll try to figgure out what the issues is and report back.
Saying we implemented it is probably an exaggeration The quantity system basically attaches a number to a unit and knows that e.g. if you add two quantities, the numbers add, but the units don’t change (and have to be the same) – so this means that we don’t really care about whether the numbers are floats or complex, Python/numpy takes care of these calculations.
There are certainly places where our assumption about the numbers being floats “leaks through”, but those shouldn’t be that hard to fix.
The error you are seeing is one of these places: we sometimes use the shorthand np.float(q)
to remove the units from a quantity and get the “pure numpy” array. This obviously fails for a complex number, but instead of np.float
we could also use np.asarray
(which we do in a number of other places), which should fix your specific error.
I don’t think it’s an installation issue, your atom/hydrogen
setup simply seems to support fancy LaTeX representations, and the generation of this representation fails – print(brian2.Hz * 1j)
probably works just fine.