Как я могу выполнить умножение матриц на количество пинты Количество в Python 3? - PullRequest
1 голос
/ 28 марта 2019

Я бы хотел умножить (3, 3) np.matrix на (3,1) np.matrix, который включает pint Количество информации.

Этот код работает:

import numpy as np
x = np.mat([[1,0,0],[0,1,0],[0,0,1]])
y = np.mat([[1],[0],[0]])
x * y
>>> x * y
matrix([[1],
        [0],
        [0]])

Этот код выдает ошибку:

import numpy as np
import pint
ureg = pint.UnitRegistry()
x = np.mat([[1,0,0],[0,1,0],[0,0,1]])
y = np.mat([[1],[0],[0]]) * ureg("m")
x * y

Ошибка:

>>> x * y
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    x * y
  File "~/.virtualenvs/py3env/lib/python3.7/site-package
s/pint/quantity.py", line 900, in __mul__
    return self._mul_div(other, operator.mul)
  File "~/.virtualenvs/py3env/lib/python3.7/site-package
s/pint/quantity.py", line 75, in wrapped
    result = f(self, *args, **kwargs)
  File "~/.virtualenvs/py3env/lib/python3.7/site-package
s/pint/quantity.py", line 60, in wrapped
    result = f(self, *args, **kwargs)
  File "~/.virtualenvs/py3env/lib/python3.7/site-package
s/pint/quantity.py", line 866, in _mul_div
    magnitude = magnitude_op(self._magnitude, other_magnitude)
  File "~/.virtualenvs/py3env/lib/python3.7/site-package
s/numpy/matrixlib/defmatrix.py", line 215, in __mul__
    return N.dot(self, asmatrix(other))
ValueError: shapes (3,1) and (3,3) not aligned: 1 (dim 1) != 3 (dim 0)

ЕслиЯ использую np.dot() Я получаю результат, но единицы были убраны

>>> np.dot(x, y)
~/.virtualenvs/py3env/lib/python3.7/site-packages/pint/q
uantity.py:1377: UnitStrippedWarning: The unit of the quantity is stripped
.
  warnings.warn("The unit of the quantity is stripped.", UnitStrippedWarni
ng)
matrix([[1],
        [0],
        [0]])

Это ожидаемое поведение?Могу ли я использовать математику NumPy с pint Количествами?Есть ли способ сделать это?

Я использую Python 3.7 Numpy == 1.15.2 Пинта == 0.9

1 Ответ

1 голос
/ 29 марта 2019

Как указал hpaulj, класс количества пинт меняет порядок на y * x.

Это потому, что пинта не создает отдельной функции для правильного умножения rmul и использует __rmul__ = __mul__

Есть несколько способов решить эту проблему

Решение 1

Мне удалось решить эту проблему, изменив pint / amount.py, чтобы получить отдельную личность. rmul function

    def __mul__(self, other):
        return self._mul_div(other, operator.mul)

    def __rmul__(self, other):
        return self._mul_div(other, operator.mul, rmul=True)

    # __rmul__ = __mul__

и изменение self._mul_div для необязательного обмена self и other с двумя изменениями:

    @check_implemented
    @ireduce_dimensions
    def _mul_div(self, other, magnitude_op, units_op=None, rmul=False):
        """Perform multiplication or division operation and return the result.

        :param other: object to be multiplied/divided with self
        :type other: Quantity or any type accepted by :func:`_to_magnitude`
        :param magnitude_op: operator function to perform on the magnitudes
            (e.g. operator.mul)
        :type magnitude_op: function
        :param units_op: operator function to perform on the units; if None,
            *magnitude_op* is used
        :type units_op: function or None
        :param rmul: for self.__rmul__ which means the multiplication is 
        happening like:         other * self  
        rather than the normal: self. * other
        """
        print(F"self is {self} other is {other}")
        if units_op is None:
            units_op = magnitude_op

        offset_units_self = self._get_non_multiplicative_units()
        no_offset_units_self = len(offset_units_self)

        if not self._check(other):

            if not self._ok_for_muldiv(no_offset_units_self):
                raise OffsetUnitCalculusError(self._units,
                                              getattr(other, 'units', ''))
            if len(offset_units_self) == 1:
                if (self._units[offset_units_self[0]] != 1
                        or magnitude_op not in [operator.mul, operator.imul]):
                    raise OffsetUnitCalculusError(self._units,
                                                  getattr(other, 'units', ''))
            try:
                other_magnitude = _to_magnitude(other, self.force_ndarray)
            except TypeError:
                return NotImplemented

            # ++++++++++++++++++++++++++++++++++++++++++++++++
            # +++++++++++++++ Change 1 +++++++++++++++++++++++
            # ++++++++++++++++++++++++++++++++++++++++++++++++
            # magnitude = magnitude_op(self._magnitude, other_magnitude)
            op_params = (other_magnitude, self._magnitude) if rmul else (self._magnitude, other_magnitude)
            magnitude = magnitude_op(*op_params)
            # ++++++++++++++++++++++++++++++++++++++++++++++++
            # +++++++++++++++ End Change 1  ++++++++++++++++++
            # ++++++++++++++++++++++++++++++++++++++++++++++++
            units = units_op(self._units, UnitsContainer())

            return self.__class__(magnitude, units)

        if isinstance(other, self._REGISTRY.Unit):
            other = 1.0 * other

        new_self = self

        if not self._ok_for_muldiv(no_offset_units_self):
            raise OffsetUnitCalculusError(self._units, other._units)
        elif no_offset_units_self == 1 and len(self._units) == 1:
            new_self = self.to_root_units()

        no_offset_units_other = len(other._get_non_multiplicative_units())

        if not other._ok_for_muldiv(no_offset_units_other):
            raise OffsetUnitCalculusError(self._units, other._units)
        elif no_offset_units_other == 1 and len(other._units) == 1:
            other = other.to_root_units

        # ++++++++++++++++++++++++++++++++++++++++++++++++
        # +++++++++++++++ Change 2 +++++++++++++++++++++++
        # ++++++++++++++++++++++++++++++++++++++++++++++++
        # magnitude = magnitude_op(new_self._magnitude, other._magnitude)
        op_params = (other._magnitude, new_self._magnitude) if rmul else (new_self._magnitude, other._magnitude)
        magnitude = magnitude_op(*op_params)
        # ++++++++++++++++++++++++++++++++++++++++++++++++
        # +++++++++++++++ End Change 2  ++++++++++++++++++
        # ++++++++++++++++++++++++++++++++++++++++++++++++
        units = units_op(new_self._units, other._units)

        return self.__class__(magnitude, units)

Решение 2

Если вы сделаете x безразмерное количество пинты, умножение будет дано в правильном порядке.

import numpy as np
import pint
ureg = pint.UnitRegistry()
x = np.mat([[1,0,0],[0,1,0],[0,0,1]]) *ureg("")
y = np.mat([[1],[0],[0]]) * ureg("m")
>>> x * y
<Quantity([[1]
 [0]
 [0]], 'meter')>
...