Skip to content

Commit 61371f6

Browse files
Merge branch 'master' into docs-prompt-docstring
2 parents 3450429 + dd86a88 commit 61371f6

11 files changed

Lines changed: 1218 additions & 569 deletions

File tree

.github/workflows/build.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,14 @@ jobs:
2121
allow-prereleases: true
2222
- run: uv sync --group=test
2323
- name: Run tests
24-
# TODO: #8818 Re-enable quantum tests
2524
run: uv run --with=pytest-run-parallel pytest
2625
--iterations=8 --parallel-threads=auto
2726
--ignore=computer_vision/cnn_classification.py
2827
--ignore=docs/conf.py
2928
--ignore=dynamic_programming/k_means_clustering_tensorflow.py
30-
--ignore=machine_learning/local_weighted_learning/local_weighted_learning.py
3129
--ignore=machine_learning/lstm/lstm_prediction.py
3230
--ignore=neural_network/input_data.py
3331
--ignore=project_euler/
34-
--ignore=quantum/q_fourier_transform.py
3532
--ignore=scripts/validate_solutions.py
3633
--ignore=web_programming/current_stock_price.py
3734
--ignore=web_programming/fetch_anime_and_play.py

.pre-commit-config.yaml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,21 @@ repos:
2121
hooks:
2222
- id: auto-walrus
2323

24-
- repo: https://github.com/astral-sh/uv-pre-commit
25-
rev: 0.12.7
26-
hooks:
27-
- id: uv-lock
28-
29-
- repo: https://github.com/astral-sh/ruff-pre-commit
30-
rev: v0.16.1
31-
hooks:
32-
- id: ruff-check
33-
- id: ruff-format
34-
3524
- repo: https://github.com/codespell-project/codespell
3625
rev: v2.4.3
3726
hooks:
3827
- id: codespell
3928
additional_dependencies:
4029
- tomli
4130

31+
- repo: https://github.com/astral-sh/ruff-pre-commit
32+
rev: v0.16.5
33+
hooks:
34+
- id: ruff-check
35+
- id: ruff-format
36+
4237
- repo: https://github.com/tox-dev/pyproject-fmt
43-
rev: v2.26.0
38+
rev: v2.28.1
4439
hooks:
4540
- id: pyproject-fmt
4641

@@ -52,8 +47,13 @@ repos:
5247
language: script
5348
pass_filenames: false
5449

50+
- repo: https://github.com/astral-sh/uv-pre-commit
51+
rev: 0.12.7
52+
hooks:
53+
- id: uv-lock
54+
5555
- repo: https://github.com/abravalheri/validate-pyproject
56-
rev: v0.25
56+
rev: "0.26"
5757
hooks:
5858
- id: validate-pyproject
5959

AGENTS.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# AGENTS.md
2+
3+
Guidance for AI coding agents (and their humans) contributing to
4+
**TheAlgorithms/Python**. This complements — and never overrides —
5+
[`CONTRIBUTING.md`](CONTRIBUTING.md). Read that first.
6+
7+
This repository is educational: implementations should be clear and correct
8+
rather than maximally optimized. Every change goes through CI and the
9+
`algorithms-keeper` bot, both of which reject non-conforming PRs automatically.
10+
11+
## Before opening a pull request
12+
13+
- **Check at least one box in the PR description.** The `algorithms-keeper`
14+
bot **closes any PR whose "Describe your change" section has no checked
15+
box** (`* [x]`). Fill in the template that ships in
16+
`.github/pull_request_template.md` and tick every item that applies before
17+
you submit — this is the single most common reason automated PRs get closed.
18+
- **One algorithm file per PR.** Split unrelated changes into separate PRs to
19+
keep review focused.
20+
- **Don't change code and its doctests in the same PR.** If you're only
21+
updating tests, say so and touch nothing else.
22+
23+
## Code conventions (enforced by CI)
24+
25+
- **Formatting & linting:** `ruff` (`uvx ruff check .` and `uvx ruff format .`).
26+
Run `uvx pre-commit run --all-files` locally to catch everything CI will.
27+
- **Type hints:** annotate every function parameter and return value with
28+
[type hints](https://docs.python.org/3/library/typing.html).
29+
- **Doctests:** every function needs at least one
30+
[doctest](https://docs.python.org/3/library/doctest.html) that passes under
31+
`python -m doctest -v your_file.py` (and `pytest`).
32+
- **Naming:** filenames are all-lowercase with underscores (no spaces or
33+
dashes); functions and variables follow standard Python naming.
34+
- **Placement:** new files go inside an existing directory.
35+
- **References:** new algorithms include a URL to Wikipedia or a comparable
36+
explanation.
37+
38+
## Running the suite locally
39+
40+
This project is managed with [`uv`](https://docs.astral.sh/uv/) — there is no
41+
`requirements.txt`. Dependencies live in `pyproject.toml`/`uv.lock`, and `uvx`
42+
runs a tool in a throwaway environment without polluting yours:
43+
44+
```bash
45+
uvx pre-commit run --all-files # ruff, formatting, hooks
46+
uvx pytest your_module/your_file.py --doctest-modules
47+
```
48+
49+
(`uv run pytest ...` works too if you'd rather use the project's locked
50+
environment.)
51+
52+
Some directories are intentionally skipped in CI (`--ignore` entries in
53+
`.github/workflows/build.yml`), usually because a heavy dependency lacks a
54+
wheel for the CPython version the repo currently targets. Check that list
55+
before assuming a file is untested.
56+
57+
## Good agent behavior
58+
59+
- Keep diffs minimal and scoped to the stated change.
60+
- Preserve existing style and structure; prefer clarity over cleverness.
61+
- Never fabricate doctest output — run it and paste the real result.
62+
- If CI is red, read the log and fix the cause rather than re-running blindly.

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ We want your work to be readable by others; therefore, we encourage you to note
108108
The following are considered to be bad and may be requested to be improved:
109109

110110
```python
111-
x = x + 2 # increased by 2
111+
x = x + 2 # increased by 2
112112
```
113113

114114
This is too trivial. Comments are expected to be explanatory. For comments, you can write them above, on or below a line of code, as long as you are consistent within the same piece of code.
@@ -148,7 +148,7 @@ We want your work to be readable by others; therefore, we encourage you to note
148148
The use of the Python built-in `input()` function is __not__ encouraged:
149149

150150
```python
151-
input('Enter your input:')
151+
input("Enter your input:")
152152
# Or even worse...
153153
input = eval(input("Enter your input: "))
154154
```

DIRECTORY.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
## Audio Filters
33
* [Butterworth Filter](audio_filters/butterworth_filter.py)
4+
* [Equal Loudness Filter](audio_filters/equal_loudness_filter.py)
45
* [Iir Filter](audio_filters/iir_filter.py)
56
* [Show Response](audio_filters/show_response.py)
67

@@ -451,9 +452,11 @@
451452
* [Time And Half Pay](financial/time_and_half_pay.py)
452453

453454
## Fractals
455+
* [Barnsley Fern](fractals/barnsley_fern.py)
454456
* [Julia Sets](fractals/julia_sets.py)
455457
* [Koch Snowflake](fractals/koch_snowflake.py)
456458
* [Mandelbrot](fractals/mandelbrot.py)
459+
* [Sierpinski Carpet](fractals/sierpinski_carpet.py)
457460
* [Sierpinski Triangle](fractals/sierpinski_triangle.py)
458461
* [Vicsek](fractals/vicsek.py)
459462

@@ -843,8 +846,10 @@
843846
* [Validate Sudoku Board](matrix/validate_sudoku_board.py)
844847

845848
## Networking Flow
849+
* [Dinic](networking_flow/dinic.py)
846850
* [Ford Fulkerson](networking_flow/ford_fulkerson.py)
847851
* [Minimum Cut](networking_flow/minimum_cut.py)
852+
* [Push Relabel](networking_flow/push_relabel.py)
848853

849854
## Neural Network
850855
* Activation Functions
@@ -1372,6 +1377,7 @@
13721377
* [Split](strings/split.py)
13731378
* [String Switch Case](strings/string_switch_case.py)
13741379
* [Strip](strings/strip.py)
1380+
* [Suffix Automaton](strings/suffix_automaton.py)
13751381
* [Text Justification](strings/text_justification.py)
13761382
* [Title](strings/title.py)
13771383
* [Top K Frequent Words](strings/top_k_frequent_words.py)

machine_learning/local_weighted_learning/local_weighted_learning.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ def weight_matrix(point: np.ndarray, x_train: np.ndarray, tau: float) -> np.ndar
5050
m x m weight matrix around the prediction point, where m is the size of
5151
the training set
5252
>>> weight_matrix(
53-
... np.array([1., 1.]),
54-
... np.array([[16.99, 10.34], [21.01,23.68], [24.59,25.69]]),
55-
... 0.6
56-
... )
57-
array([[1.43807972e-207, 0.00000000e+000, 0.00000000e+000],
58-
[0.00000000e+000, 0.00000000e+000, 0.00000000e+000],
59-
[0.00000000e+000, 0.00000000e+000, 0.00000000e+000]])
53+
... np.array([16.99, 10.34]),
54+
... np.array([[16.99, 10.34], [21.01, 23.68], [24.59, 25.69]]),
55+
... 5,
56+
... ).round(4)
57+
array([[1. , 0. , 0. ],
58+
[0. , 0.0206, 0. ],
59+
[0. , 0. , 0.0028]])
6060
"""
6161
m = len(x_train) # Number of training samples
6262
weights = np.eye(m) # Initialize weights as identity matrix
@@ -83,13 +83,13 @@ def local_weight(
8383
Returns:
8484
ndarray of local weights
8585
>>> local_weight(
86-
... np.array([1., 1.]),
87-
... np.array([[16.99, 10.34], [21.01,23.68], [24.59,25.69]]),
86+
... np.array([16.99, 10.34]),
87+
... np.array([[16.99, 10.34], [21.01, 23.68], [24.59, 25.69]]),
8888
... np.array([[1.01, 1.66, 3.5]]),
89-
... 0.6
90-
... )
91-
array([[0.00873174],
92-
[0.08272556]])
89+
... 5,
90+
... ).round(5)
91+
array([[0.02572],
92+
[0.05552]])
9393
"""
9494
weight_mat = weight_matrix(point, x_train, tau)
9595
weight = np.linalg.inv(x_train.T @ weight_mat @ x_train) @ (
@@ -116,9 +116,9 @@ def local_weight_regression(
116116
>>> local_weight_regression(
117117
... np.array([[16.99, 10.34], [21.01, 23.68], [24.59, 25.69]]),
118118
... np.array([[1.01, 1.66, 3.5]]),
119-
... 0.6
120-
... )
121-
array([1.07173261, 1.65970737, 3.50160179])
119+
... 5,
120+
... ).round(5)
121+
array([1.01094, 1.98589, 3.42233])
122122
"""
123123
y_pred = np.zeros(len(x_train)) # Initialize array of predictions
124124
for i, item in enumerate(x_train):

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ classifiers = [
99
"Programming Language :: Python :: 3.14",
1010
]
1111
dependencies = [
12-
"beautifulsoup4>=4.12.3",
12+
"beautifulsoup4>=4.15",
1313
"cython>=3.1.2",
1414
"fake-useragent>=1.5.1",
1515
"httpx>=0.28.1",
@@ -21,6 +21,7 @@ dependencies = [
2121
"opencv-python>=4.10.0.84",
2222
"pandas>=2.2.3",
2323
"pillow>=11.3",
24+
"qiskit>=2",
2425
"rich>=13.9.4",
2526
"scikit-learn>=1.5.2",
2627
"scipy>=1.16.2",

quantum/q_fourier_transform.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
11
"""
2-
Build the quantum fourier transform (qft) for a desire
3-
number of quantum bits using Qiskit framework. This
4-
experiment run in IBM Q simulator with 10000 shots.
5-
This circuit can be use as a building block to design
6-
the Shor's algorithm in quantum computing. As well as,
7-
quantum phase estimation among others.
8-
.
2+
Build the quantum Fourier transform (QFT) for a desired
3+
number of qubits using the Qiskit framework.
4+
5+
This circuit can be used as a building block to design
6+
Shor's algorithm in quantum computing, as well as
7+
quantum phase estimation, among others.
8+
9+
The circuit is simulated with Qiskit's built-in, pure-Python
10+
``BasicSimulator`` (no compiled ``qiskit-aer`` backend required),
11+
so it runs anywhere Qiskit itself installs.
12+
913
References:
1014
https://en.wikipedia.org/wiki/Quantum_Fourier_transform
11-
https://qiskit.org/textbook/ch-algorithms/quantum-fourier-transform.html
15+
https://quantum.cloud.ibm.com/docs/en/api/qiskit/qiskit.circuit.library.QFT
1216
"""
1317

1418
import math
1519

1620
import numpy as np
1721
import qiskit
18-
from qiskit import Aer, ClassicalRegister, QuantumCircuit, QuantumRegister, execute
22+
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister, transpile
23+
from qiskit.providers.basic_provider import BasicSimulator
1924

2025

2126
def quantum_fourier_transform(number_of_qubits: int = 3) -> qiskit.result.counts.Counts:
2227
"""
23-
# >>> quantum_fourier_transform(2)
24-
# {'00': 2500, '01': 2500, '11': 2500, '10': 2500}
28+
Build and simulate the quantum Fourier transform applied to the all-zero
29+
state ``|0...0>``. The QFT maps ``|0...0>`` to a uniform superposition, so
30+
every computational-basis outcome is (up to shot noise) equally likely.
31+
2532
# quantum circuit for number_of_qubits = 3:
2633
┌───┐
2734
qr_0: ──────■──────────────────────■───────┤ H ├─X─
@@ -31,13 +38,20 @@ def quantum_fourier_transform(number_of_qubits: int = 3) -> qiskit.result.counts
3138
qr_2: ┤ H ├─■────────■───────────────────────────X─
3239
└───┘
3340
cr: 3/═════════════════════════════════════════════
41+
3442
Args:
35-
n : number of qubits
43+
number_of_qubits : number of qubits
44+
3645
Returns:
37-
qiskit.result.counts.Counts: distribute counts.
46+
qiskit.result.counts.Counts: measurement counts over 10,000 shots.
3847
39-
>>> quantum_fourier_transform(2)
40-
{'00': 2500, '01': 2500, '10': 2500, '11': 2500}
48+
The simulation is seeded, so the set of observed outcomes is reproducible:
49+
50+
>>> counts = quantum_fourier_transform(2)
51+
>>> sorted(counts)
52+
['00', '01', '10', '11']
53+
>>> sum(counts.values())
54+
10000
4155
>>> quantum_fourier_transform(-1)
4256
Traceback (most recent call last):
4357
...
@@ -82,9 +96,12 @@ def quantum_fourier_transform(number_of_qubits: int = 3) -> qiskit.result.counts
8296

8397
# measure all the qubits
8498
quantum_circuit.measure(qr, cr)
85-
# simulate with 10000 shots
86-
backend = Aer.get_backend("qasm_simulator")
87-
job = execute(quantum_circuit, backend, shots=10000)
99+
100+
# simulate with 10000 shots on the pure-Python BasicSimulator; seed the run
101+
# so the observed outcomes are reproducible for the doctest above.
102+
backend = BasicSimulator()
103+
transpiled_circuit = transpile(quantum_circuit, backend)
104+
job = backend.run(transpiled_circuit, shots=10_000, seed_simulator=42)
88105

89106
return job.result().get_counts(quantum_circuit)
90107

sorts/pancake_sort.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@
88
python pancake_sort.py
99
"""
1010

11+
from collections.abc import Sequence
12+
from typing import TypeVar
1113

12-
def pancake_sort(arr):
14+
T = TypeVar("T")
15+
16+
17+
def pancake_sort[T](arr: Sequence[T]) -> list[T]:
1318
"""Sort Array with Pancake Sort.
1419
:param arr: Collection containing comparable items
1520
:return: Collection ordered in ascending order of items

0 commit comments

Comments
 (0)