Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ repos:
hooks:
- id: pyupgrade
args: [--py310-plus]
- repo: https://github.com/hhatto/autopep8
rev: v2.3.2
hooks:
- id: autopep8
- repo: https://github.com/PyCQA/flake8
rev: 7.3.0
hooks:
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## [1.5.0] - 2026-04-15

### Added

- 2nd and `p` matrix norms

### Removed

- `autopep8` from `pre-commit` config

## [1.4.0] - 2026-03-31

### Added
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ To export given solution use:
### Matrix multiplication

* [Traditional matrix multiplication algorithm](matrix_calculus/matrix_multiplier.py)

### LU decomposition

### Gaussian elimination

### Matrix norms
49 changes: 49 additions & 0 deletions matrix_calculus/matrix_norms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from __future__ import annotations

import numpy as np


def second_norm(matrix: np.array):
singular_values = np.linalg.svd(matrix, compute_uv=False)
s = np.linalg.svd(matrix, compute_uv=False)
m_2 = np.max(singular_values)
condition_number = s.max() / s.min()

return m_2, condition_number


def p_norm(matrix: np.array, p: int, n_samples: int = 1000, cond_number=True):

n = matrix.shape[1]
max_val = 0.0
if cond_number:
condidion_number = np.inf

# Search for max value of the norm calculated from matrix multiplied by a randomly generated vector
for _ in range(n_samples):
# create random vector
x = np.random.randn(n)

# normalize vector in p-norm
norm_x = np.linalg.norm(x, ord=p)
if norm_x == 0:
continue
x = x / norm_x

# calculate norm from vector equal to matrix * random vector
matrix_x = matrix @ x
val = np.linalg.norm(matrix_x, ord=p)

if val > max_val:
max_val = val

if cond_number:
try:
matrix_inv = np.linalg.inv(matrix)
norm_M_inv = p_norm(matrix_inv, p, n_samples, cond_number=False)
condidion_number = max_val * norm_M_inv
except np.linalg.LinAlgError:
condidion_number = np.inf

res = (max_val, condidion_number) if cond_number else max_val
return res
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "matrix_calculus"
version = "1.4.0"
version = "1.5.0"
description = "Matrix calculus toolkit"
requires-python = ">=3.10"
dependencies = ["numpy", "seaborn", "matplotlib", "weasyprint", "markdown"]
Expand Down
Binary file added reports/imgs/matrix_p_norm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions reports/matrix_norms_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Normy Macierzowe

*Autorzy: Maja Byrecka, Michał Kowalczyk*

## Norma 2

### Algorytm

```
1. Znajdź wartości własne macierzy M
2. Zwróć maksymalną wartość własną
```

### Kod

```python3
def second_norm(matrix: np.array) -> float:
singular_values = np.linalg.svd(matrix, compute_uv=False)
return np.max(singular_values)
```

### Wynik dla Macierzy M

Dla macierzy M = [[4, 9, 2], [3, 5, 7], [8, 1, 6]], norma macierzowa wyznaczona w powyższy sposób, z parametrem `p=2` wynosiła `15.000000000000002`.

## Dowolna Norma P

Dowolną normę *p* można obliczyć jako:

![Źródło: Wykład - Wartości i wektory własne & Dekompozycja na wartości osobliwe 2026, Maciej Paszyński](imgs/matrix_p_norm.png)
*Źródło: Wykład - Wartości i wektory własne & Dekompozycja na wartości osobliwe 2026, Maciej Paszyński*

### Pseudokod

```
1. max_val <- 0; n <- ilość kolumn macierzy M
2. Powtórz zadaną ilość razy:
2.1. Utwórz losowy wektor x
2.2. Oblicz p-normę wektora x
2.3. Znormalizuj wektor x w zadanej normie
2.4. matrix_x <- matrix @ x
2.5. matrix_p <- p-norma wektora matrix_x
2.6. Jeśli matrix_p>max_val:
2.6.1. max_val <- matrix_p
3. Zwróć max_val
```

### Algorytm

```python
def p_norm(matrix: np.array, p: int, n_samples: int =1000):

n = matrix.shape[1]
max_val = 0.0

# Search for max value of the norm calculated from matrix multiplied by a randomly generated vector
for _ in range(n_samples):
# create random vector
x = np.random.randn(n)

# normalize vector in p-norm
norm_x = np.linalg.norm(x, ord=p)
if norm_x == 0:
continue
x = x / norm_x

# calculate norm from vector equal to matrix * random vector
matrix_x = matrix @ x
val = np.linalg.norm(matrix_x, ord=p)

if val > max_val:
max_val = val

return max_val
```

### Wynik dla Macierzy M

Dla macierzy M = [[4, 9, 2], [3, 5, 7], [8, 1, 6]], norma macierzowa wyznaczona w powyższy sposób, z parametrem `p=2` wynosiła `14.99203`.

---

Wykonanie:

* Język: Python3
* Podział zadań:
* Norma 2, p - Maja Byrecka
* Norma 1, inf - Michał Kowalczyk
77 changes: 77 additions & 0 deletions reports/resources/matrix-norms/code.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

========== matrix_norms_test.py ==========
from __future__ import annotations

import numpy as np
import pytest # noqa: F401
from scipy.linalg import norm

from matrix_calculus.matrix_norms import second_norm, p_norm


def test_m_2_norm():
matrix = np.array([[4, 9, 2], [3, 5, 7], [8, 1, 6]])
m_2, condition_number = second_norm(matrix)
assert np.allclose(m_2, 15.0)

matrix = np.array([[1, 2, 3], [3, 2, 1], [10, 15, 20]])
m_2, condition_number = second_norm(matrix)
assert np.allclose(m_2, 27.343, rtol=0.01)

def test_p_norm_2():
matrix = np.array([[4, 9, 2], [3, 5, 7], [8, 1, 6]])
m_2, condition_number = p_norm(matrix, p=2)
assert np.allclose(m_2, 15.0, rtol=0.01)

matrix = np.array([[1, 2, 3], [3, 2, 1], [10, 15, 20]])
m_2, condition_number = p_norm(matrix, p=2)
assert np.allclose(m_2, 27.343, rtol=0.01)


========== matrix_norms.py ==========
import numpy as np


def second_norm(matrix: np.array) -> float:
singular_values = np.linalg.svd(matrix, compute_uv=False)
s = np.linalg.svd(matrix, compute_uv=False)
m_2 = np.max(singular_values)
condition_number = s.max() / s.min()

return m_2, condition_number

def p_norm(matrix: np.array, p: int, n_samples: int =1000, cond_number=True):

n = matrix.shape[1]
max_val = 0.0
if cond_number:
condidion_number = np.inf

# Search for max value of the norm calculated from matrix multiplied by a randomly generated vector
for _ in range(n_samples):
# create random vector
x = np.random.randn(n)

# normalize vector in p-norm
norm_x = np.linalg.norm(x, ord=p)
if norm_x == 0:
continue
x = x / norm_x

# calculate norm from vector equal to matrix * random vector
matrix_x = matrix @ x
val = np.linalg.norm(matrix_x, ord=p)

if val > max_val:
max_val = val

if cond_number:
try:
matrix_inv = np.linalg.inv(matrix)
norm_M_inv = p_norm(matrix_inv, p, n_samples, cond_number = False)
condidion_number = max_val * norm_M_inv
except np.linalg.LinAlgError:
condidion_number = np.inf

res = (max_val, condidion_number) if cond_number else max_val
return res
Binary file added reports/resources/matrix-norms/report.pdf
Binary file not shown.
27 changes: 27 additions & 0 deletions tests/matrix_norms_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from __future__ import annotations

import numpy as np
import pytest # noqa: F401

from matrix_calculus.matrix_norms import p_norm
from matrix_calculus.matrix_norms import second_norm


def test_m_2_norm():
matrix = np.array([[4, 9, 2], [3, 5, 7], [8, 1, 6]])
m_2, condition_number = second_norm(matrix)
assert np.allclose(m_2, 15.0)

matrix = np.array([[1, 2, 3], [3, 2, 1], [10, 15, 20]])
m_2, condition_number = second_norm(matrix)
assert np.allclose(m_2, 27.343, rtol=0.01)


def test_p_norm_2():
matrix = np.array([[4, 9, 2], [3, 5, 7], [8, 1, 6]])
m_2, condition_number = p_norm(matrix, p=2)
assert np.allclose(m_2, 15.0, rtol=0.01)

matrix = np.array([[1, 2, 3], [3, 2, 1], [10, 15, 20]])
m_2, condition_number = p_norm(matrix, p=2)
assert np.allclose(m_2, 27.343, rtol=0.01)
Loading