Skip to content

Commit eca5681

Browse files
authored
Merge branch 'master' into fix-exponential-search-empty-list
2 parents 0bc8059 + 5bd6b19 commit eca5681

8 files changed

Lines changed: 201 additions & 8 deletions

File tree

DIRECTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@
110110
## [Blockchain](blockchain)
111111
* [Diophantine Equation](blockchain/diophantine_equation.py)
112112
* [Merkle Tree](blockchain/merkle_tree.py)
113+
* [Proof Of Stake](blockchain/proof_of_stake.py)
114+
* [Proof Of Work](blockchain/proof_of_work.py)
113115
* [Simple Blockchain](blockchain/simple_blockchain.py)
114116
* [Simple Proof Of Work](blockchain/simple_proof_of_work.py)
115117

@@ -638,6 +640,7 @@
638640
* [Strongly Connected Components](graphs/strongly_connected_components.py)
639641
* [Tarjans Scc](graphs/tarjans_scc.py)
640642
* Tests
643+
* [Test Graphs Floyd Warshall](graphs/tests/test_graphs_floyd_warshall.py)
641644
* [Test Johnson](graphs/tests/test_johnson.py)
642645
* [Test Min Spanning Tree Kruskal](graphs/tests/test_min_spanning_tree_kruskal.py)
643646
* [Test Min Spanning Tree Prim](graphs/tests/test_min_spanning_tree_prim.py)

blockchain/proof_of_stake.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import random
2+
3+
4+
class Validator:
5+
def __init__(self, name: str, stake: int) -> None:
6+
"""
7+
Initializes a new validator with a given name and stake.
8+
9+
Args:
10+
name (str): The name of the validator.
11+
stake (int): The amount of stake the validator has.
12+
"""
13+
self.name = name
14+
self.stake = stake
15+
16+
17+
def choose_validator(validators: list[Validator]) -> Validator:
18+
"""
19+
Selects a validator to create the next block based on the weight of their stake.
20+
21+
The higher the stake, the greater the chance to be selected.
22+
23+
Args:
24+
validators (list[Validator]): A list of Validator objects.
25+
26+
Returns:
27+
Validator: The selected validator based on weighted random selection.
28+
29+
Example:
30+
>>> validators = [Validator("Alice", 50), Validator("Bob", 30)]
31+
>>> chosen = choose_validator(validators)
32+
>>> isinstance(chosen, Validator)
33+
True
34+
"""
35+
total_stake = sum(v.stake for v in validators)
36+
weighted_validators = [(v, v.stake / total_stake) for v in validators]
37+
selected = random.choices(
38+
[v[0] for v in weighted_validators], weights=[v[1] for v in weighted_validators]
39+
)
40+
return selected[0]

blockchain/proof_of_work.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import hashlib
2+
3+
4+
def proof_of_work(difficulty: int) -> int:
5+
"""
6+
Simulates a Proof of Work mining process.
7+
8+
The miner must find a nonce such that the hash of the nonce starts
9+
with a specific number of leading zeros (difficulty).
10+
11+
Args:
12+
difficulty (int): The number of leading zeros required in the hash.
13+
14+
Returns:
15+
int: The nonce value that solves the puzzle.
16+
17+
Example:
18+
>>> result = proof_of_work(2) # Difficulty of 2 should be fast
19+
>>> isinstance(result, int)
20+
True
21+
"""
22+
prefix = "0" * difficulty
23+
nonce = 0
24+
25+
while True:
26+
hash_result = hashlib.sha256(f"{nonce}".encode()).hexdigest()
27+
if hash_result.startswith(prefix):
28+
return nonce
29+
nonce += 1

graphs/graphs_floyd_warshall.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ def _print_dist(dist, v) -> None:
99
print("\nThe shortest path matrix using Floyd Warshall algorithm\n")
1010
for i in range(v):
1111
for j in range(v):
12+
end_char = "" if j == v - 1 else " "
1213
if dist[i][j] != float("inf"):
13-
print(int(dist[i][j]), end="\t")
14+
print(int(dist[i][j]), end=end_char)
1415
else:
15-
print("INF", end="\t")
16+
print("INF", end=end_char)
1617
print()
1718

1819

@@ -31,6 +32,28 @@ def floyd_warshall(graph, v):
3132
4. The above is repeated for each vertex k in the graph.
3233
5. Whenever distance[i][j] is given a new minimum value, next vertex[i][j] is
3334
updated to the next vertex[i][k].
35+
36+
37+
>>> graph = [
38+
... [0, 3, float('inf')],
39+
... [2, 0, float('inf')],
40+
... [float('inf'), 7, 0]
41+
... ]
42+
43+
>>> expected = [
44+
... [0, 3, float('inf')],
45+
... [2, 0, float('inf')],
46+
... [9, 7, 0]
47+
... ]
48+
>>> dist, _ = floyd_warshall(graph, 3)
49+
<BLANKLINE>
50+
The shortest path matrix using Floyd Warshall algorithm
51+
<BLANKLINE>
52+
0 3 INF
53+
2 0 INF
54+
9 7 0
55+
>>> dist == expected
56+
True
3457
"""
3558

3659
dist = [[float("inf") for _ in range(v)] for _ in range(v)]
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import pytest
2+
3+
from graphs.graphs_floyd_warshall import floyd_warshall
4+
5+
6+
def test_no_edges():
7+
graph = [
8+
[0, float("inf"), float("inf")],
9+
[float("inf"), 0, float("inf")],
10+
[float("inf"), float("inf"), 0],
11+
]
12+
expected = [
13+
[0, float("inf"), float("inf")],
14+
[float("inf"), 0, float("inf")],
15+
[float("inf"), float("inf"), 0],
16+
]
17+
dist, _ = floyd_warshall(graph, 3)
18+
assert dist == expected
19+
20+
21+
def test_with_edges():
22+
graph = [[0, 3, float("inf")], [2, 0, float("inf")], [float("inf"), 7, 0]]
23+
expected = [[0, 3, float("inf")], [2, 0, float("inf")], [9, 7, 0]]
24+
dist, _ = floyd_warshall(graph, 3)
25+
assert dist == expected
26+
27+
28+
def test_unreachable_vertices():
29+
graph = [
30+
[0, 1, float("inf")],
31+
[float("inf"), 0, 2],
32+
[float("inf"), float("inf"), 0],
33+
]
34+
expected = [[0, 1, 3], [float("inf"), 0, 2], [float("inf"), float("inf"), 0]]
35+
dist, _ = floyd_warshall(graph, 3)
36+
assert dist == expected
37+
38+
39+
if __name__ == "__main__":
40+
pytest.main()

matrix/count_islands_in_matrix.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,46 @@
11
# An island in matrix is a group of linked areas, all having the same value.
22
# This code counts number of islands in a given matrix, with including diagonal
33
# connections.
4-
5-
64
class Matrix: # Public class to implement a graph
5+
"""This public class represents the 2-Dimensional matrix to count
6+
the number of islands.An island is the connected group of 1s,including the top,
7+
down, right, left as well as the diagonal connections.
8+
>>> matrix1 = Matrix(3, 3, [[1, 1, 0], [0, 1, 0], [1, 0, 1]])
9+
>>> matrix1.count_islands()
10+
1
11+
>>> matrix2 = Matrix(2, 2, [[1, 1], [1, 1]])
12+
>>> matrix2.count_islands()
13+
1
14+
"""
15+
716
def __init__(self, row: int, col: int, graph: list[list[bool]]) -> None:
17+
"""Initializes the matrix with the given number of rows, columns and matrix.
18+
Args:
19+
row (int): number of rows in the matrix
20+
col (int): number of columns in the matrix
21+
graph (list[list[bool]]): 2-D list of 0s and 1s representing the matrix
22+
"""
823
self.ROW = row
924
self.COL = col
1025
self.graph = graph
1126

1227
def is_safe(self, i: int, j: int, visited: list[list[bool]]) -> bool:
28+
"""This checks if the current cell can be included in the current island.
29+
Args:
30+
i (int): row index
31+
j (int): column index
32+
visited (list[list[bool]]): 2D list tracking the visited cells
33+
Returns:
34+
bool: True if the cell is valid and part of the island
35+
(1 for True and ) for False)
36+
>>> visited = [[False, False], [False, False]]
37+
>>> graph = [[1, 0], [0, 1]]
38+
>>> m = Matrix(2, 2, graph)
39+
>>> m.is_safe(0, 0, visited)
40+
1
41+
>>> m.is_safe(0, 1, visited)
42+
0
43+
"""
1344
return (
1445
0 <= i < self.ROW
1546
and 0 <= j < self.COL
@@ -18,6 +49,19 @@ def is_safe(self, i: int, j: int, visited: list[list[bool]]) -> bool:
1849
)
1950

2051
def diffs(self, i: int, j: int, visited: list[list[bool]]) -> None:
52+
"""This is the recursive function to mark all the cells visited which
53+
are connected to (i, j) indices.
54+
Args:
55+
i (int): row index
56+
j (int): column index
57+
visited (list[list[bool]]): 2D list tracking the visited cells
58+
>>> visited = [[False, False], [False, False]]
59+
>>> graph = [[1, 1], [0, 1]]
60+
>>> m = Matrix(2, 2, graph)
61+
>>> m.diffs(0, 0, visited)
62+
>>> visited
63+
[[True, True], [False, True]]
64+
"""
2165
# Checking all 8 elements surrounding nth element
2266
row_nbr = [-1, -1, -1, 0, 0, 1, 1, 1] # Coordinate order
2367
col_nbr = [-1, 0, 1, -1, 1, -1, 0, 1]
@@ -27,6 +71,18 @@ def diffs(self, i: int, j: int, visited: list[list[bool]]) -> None:
2771
self.diffs(i + row_nbr[k], j + col_nbr[k], visited)
2872

2973
def count_islands(self) -> int: # And finally, count all islands.
74+
"""
75+
This counts all the islands in the given matrix.
76+
Returns:
77+
int: the number of islands in the given matrix.
78+
Example -
79+
>>> mat = Matrix(1, 1, [[1]])
80+
>>> mat.count_islands()
81+
1
82+
>>> mat2 = Matrix(2, 2, [[0, 0], [0, 0]])
83+
>>> mat2.count_islands()
84+
0
85+
"""
3086
visited = [[False for j in range(self.COL)] for i in range(self.ROW)]
3187
count = 0
3288
for i in range(self.ROW):

matrix/matrix_class.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,11 @@ def cofactors(self) -> Matrix:
204204
return Matrix(
205205
[
206206
[
207-
self.minors().rows[row][column]
208-
if (row + column) % 2 == 0
209-
else self.minors().rows[row][column] * -1
207+
(
208+
self.minors().rows[row][column]
209+
if (row + column) % 2 == 0
210+
else self.minors().rows[row][column] * -1
211+
)
210212
for column in range(self.minors().num_columns)
211213
]
212214
for row in range(self.minors().num_rows)

searches/linear_search.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def rec_linear_search(sequence: list, low: int, high: int, target: int) -> int:
5555
-1
5656
"""
5757
if not (0 <= high < len(sequence) and 0 <= low < len(sequence)):
58-
raise Exception("Invalid upper or lower bound!")
58+
raise ValueError("Invalid upper or lower bound!")
5959
if high < low:
6060
return -1
6161
if sequence[low] == target:

0 commit comments

Comments
 (0)