0.12.0a1 add Matrix()
This commit is contained in:
parent
eca16d781f
commit
d123b9c196
4 changed files with 173 additions and 1 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
* New module `mat` adds a shallow reimplementation of `Matrix()` in order to implement matrix multiplication
|
||||||
|
|
||||||
## 0.11.2
|
## 0.11.2
|
||||||
|
|
||||||
+ increase test coverage of `validators`
|
+ increase test coverage of `validators`
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ from .redact import redact_url_password
|
||||||
from .http import WantsContentType
|
from .http import WantsContentType
|
||||||
from .color import chalk, WebColor
|
from .color import chalk, WebColor
|
||||||
|
|
||||||
__version__ = "0.11.2"
|
__version__ = "0.12.0a1"
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',
|
'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue',
|
||||||
|
|
|
||||||
121
src/suou/mat.py
Normal file
121
src/suou/mat.py
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
"""
|
||||||
|
Matrix (not the movie...)
|
||||||
|
|
||||||
|
*New in 0.12.0*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Copyright (c) 2025 Sakuragasaki46.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
See LICENSE for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
This software is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import Collection, Iterable, TypeVar
|
||||||
|
from .functools import deprecated
|
||||||
|
|
||||||
|
_T = TypeVar('_T')
|
||||||
|
|
||||||
|
class Matrix(Collection[_T]):
|
||||||
|
"""
|
||||||
|
Shallow reimplementation of numpy's matrices in pure Python.
|
||||||
|
|
||||||
|
*New in 0.12.0*
|
||||||
|
"""
|
||||||
|
_shape: tuple[int, int]
|
||||||
|
_elements: list[_T]
|
||||||
|
|
||||||
|
def shape(self):
|
||||||
|
return self._shape
|
||||||
|
|
||||||
|
def __init__(self, iterable: Iterable[_T] | Iterable[Collection[_T]], shape: tuple[int, int] | None = None):
|
||||||
|
elements = []
|
||||||
|
boundary_x = boundary_y = 0
|
||||||
|
for row in iterable:
|
||||||
|
if isinstance(row, Collection):
|
||||||
|
if not boundary_y:
|
||||||
|
boundary_y = len(row)
|
||||||
|
elements.extend(row)
|
||||||
|
boundary_x += 1
|
||||||
|
elif boundary_y != len(row):
|
||||||
|
raise ValueError('row length mismatch')
|
||||||
|
else:
|
||||||
|
elements.extend(row)
|
||||||
|
boundary_x += 1
|
||||||
|
elif shape:
|
||||||
|
if not boundary_x:
|
||||||
|
boundary_x, boundary_y = shape
|
||||||
|
elements.append(row)
|
||||||
|
self._shape = boundary_x, boundary_y
|
||||||
|
self._elements = elements
|
||||||
|
assert len(self._elements) == boundary_x * boundary_y
|
||||||
|
|
||||||
|
def __getitem__(self, key: tuple[int, int]) -> _T:
|
||||||
|
(x, y), (_, sy) = key, self.shape()
|
||||||
|
|
||||||
|
return self._elements[x * sy + y]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def T(self):
|
||||||
|
sx, sy = self.shape()
|
||||||
|
return Matrix(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
self[j, i] for j in range(sx)
|
||||||
|
] for i in range(sy)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def __matmul__(self, other: Matrix) -> Matrix:
|
||||||
|
(ax, ay), (bx, by) = self.shape(), other.shape()
|
||||||
|
|
||||||
|
if ay != bx:
|
||||||
|
raise ValueError('cannot multiply matrices with incompatible shape')
|
||||||
|
|
||||||
|
return Matrix([
|
||||||
|
[
|
||||||
|
sum(self[i, k] * other[k, j] for k in range(ay)) for j in range(by)
|
||||||
|
] for i in range(ax)
|
||||||
|
])
|
||||||
|
|
||||||
|
def __eq__(self, other: Matrix):
|
||||||
|
try:
|
||||||
|
return self._elements == other._elements and self._shape == other._shape
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
ax, ay = self.shape()
|
||||||
|
return ax * ay
|
||||||
|
|
||||||
|
@deprecated('please use .rows() or .columns() instead')
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self._elements)
|
||||||
|
|
||||||
|
def __contains__(self, x: object, /) -> bool:
|
||||||
|
return x in self._elements
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'{self.__class__.__name__}({list(self.rows())})'
|
||||||
|
|
||||||
|
def rows(self):
|
||||||
|
sx, sy = self.shape()
|
||||||
|
return (
|
||||||
|
[self[j, i] for j in range(sy)] for i in range(sx)
|
||||||
|
)
|
||||||
|
|
||||||
|
def columns(self):
|
||||||
|
sx, sy = self.shape()
|
||||||
|
return (
|
||||||
|
[self[j, i] for j in range(sx)] for i in range(sy)
|
||||||
|
)
|
||||||
|
|
||||||
|
## TODO write tests!
|
||||||
|
|
||||||
|
|
||||||
47
tests/test_mat.py
Normal file
47
tests/test_mat.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from suou.mat import Matrix
|
||||||
|
|
||||||
|
|
||||||
|
class TestMat(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.m_a = Matrix([
|
||||||
|
[2, 2],
|
||||||
|
[1, 3]
|
||||||
|
])
|
||||||
|
self.m_b = Matrix([
|
||||||
|
[1], [-4]
|
||||||
|
])
|
||||||
|
def tearDown(self) -> None:
|
||||||
|
...
|
||||||
|
def test_transpose(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self.m_a.T,
|
||||||
|
Matrix([
|
||||||
|
[2, 1],
|
||||||
|
[2, 3]
|
||||||
|
])
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.m_b.T,
|
||||||
|
Matrix([[1, -4]])
|
||||||
|
)
|
||||||
|
def test_mul(self):
|
||||||
|
self.assertEqual(
|
||||||
|
self.m_b.T @ self.m_a,
|
||||||
|
Matrix([
|
||||||
|
[-2, -10]
|
||||||
|
])
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.m_a @ self.m_b,
|
||||||
|
Matrix([
|
||||||
|
[-6], [-11]
|
||||||
|
])
|
||||||
|
)
|
||||||
|
def test_shape(self):
|
||||||
|
self.assertEqual(self.m_a.shape(), (2, 2))
|
||||||
|
self.assertEqual(self.m_b.shape(), (2, 1))
|
||||||
|
self.assertEqual(self.m_b.T.shape(), (1, 2))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue