Skip to content

Commit e1efda7

Browse files
authored
Merge branch 'master' into add-point-in-polygon
2 parents cbcecd2 + 78255cb commit e1efda7

13 files changed

Lines changed: 1032 additions & 25 deletions

File tree

DIRECTORY.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
## [Computer Vision](computer_vision)
182182
* [Cnn Classification](computer_vision/cnn_classification.py)
183183
* [Flip Augmentation](computer_vision/flip_augmentation.py)
184+
* [Gramian](computer_vision/gramian.py)
184185
* [Haralick Descriptors](computer_vision/haralick_descriptors.py)
185186
* [Harris Corner](computer_vision/harris_corner.py)
186187
* [Horn Schunck](computer_vision/horn_schunck.py)
@@ -231,6 +232,7 @@
231232
* [Lempel Ziv](data_compression/lempel_ziv.py)
232233
* [Lempel Ziv Decompress](data_compression/lempel_ziv_decompress.py)
233234
* [Lz77](data_compression/lz77.py)
235+
* [Move To Front](data_compression/move_to_front.py)
234236
* [Peak Signal To Noise Ratio](data_compression/peak_signal_to_noise_ratio.py)
235237
* [Run Length Encoding](data_compression/run_length_encoding.py)
236238

@@ -324,16 +326,19 @@
324326
* [From Sequence](data_structures/linked_list/from_sequence.py)
325327
* [Has Loop](data_structures/linked_list/has_loop.py)
326328
* [Is Palindrome](data_structures/linked_list/is_palindrome.py)
329+
* [Kth Element From End](data_structures/linked_list/kth_element_from_end.py)
327330
* [Merge Sort Linked List](data_structures/linked_list/merge_sort_linked_list.py)
328331
* [Merge Two Lists](data_structures/linked_list/merge_two_lists.py)
329332
* [Middle Element Of Linked List](data_structures/linked_list/middle_element_of_linked_list.py)
333+
* [Partition Linked List](data_structures/linked_list/partition_linked_list.py)
330334
* [Print Reverse](data_structures/linked_list/print_reverse.py)
331335
* [Reverse K Group](data_structures/linked_list/reverse_k_group.py)
332336
* [Rotate To The Right](data_structures/linked_list/rotate_to_the_right.py)
333337
* [Singly Linked List](data_structures/linked_list/singly_linked_list.py)
334338
* [Skip List](data_structures/linked_list/skip_list.py)
335339
* [Sorted Linked List](data_structures/linked_list/sorted_linked_list.py)
336340
* [Swap Nodes](data_structures/linked_list/swap_nodes.py)
341+
* [Xor Linked List](data_structures/linked_list/xor_linked_list.py)
337342
* Queues
338343
* [Circular Queue](data_structures/queues/circular_queue.py)
339344
* [Circular Queue Linked List](data_structures/queues/circular_queue_linked_list.py)
@@ -425,6 +430,7 @@
425430
* [Climbing Stairs](dynamic_programming/climbing_stairs.py)
426431
* [Combination Sum Iv](dynamic_programming/combination_sum_iv.py)
427432
* [Edit Distance](dynamic_programming/edit_distance.py)
433+
* [Egg Dropping](dynamic_programming/egg_dropping.py)
428434
* [Factorial](dynamic_programming/factorial.py)
429435
* [Fast Fibonacci](dynamic_programming/fast_fibonacci.py)
430436
* [Fibonacci](dynamic_programming/fibonacci.py)
@@ -542,6 +548,7 @@
542548
* Tests
543549
* [Test Graham Scan](geometry/tests/test_graham_scan.py)
544550
* [Test Jarvis March](geometry/tests/test_jarvis_march.py)
551+
* [Triangle](geometry/triangle.py)
545552

546553
## [Graphics](graphics)
547554
* [Bezier Curve](graphics/bezier_curve.py)
@@ -591,6 +598,7 @@
591598
* [Graphs Floyd Warshall](graphs/graphs_floyd_warshall.py)
592599
* [Greedy Best First](graphs/greedy_best_first.py)
593600
* [Greedy Min Vertex Cover](graphs/greedy_min_vertex_cover.py)
601+
* [Hopcroft Karp](graphs/hopcroft_karp.py)
594602
* [Johnson](graphs/johnson.py)
595603
* [Kahns Algorithm Long](graphs/kahns_algorithm_long.py)
596604
* [Kahns Algorithm Topo](graphs/kahns_algorithm_topo.py)
@@ -651,6 +659,7 @@
651659
* [Test Knapsack](knapsack/tests/test_knapsack.py)
652660

653661
## [Linear Algebra](linear_algebra)
662+
* [Gauss Jordan](linear_algebra/gauss_jordan.py)
654663
* [Gaussian Elimination](linear_algebra/gaussian_elimination.py)
655664
* [Jacobi Iteration Method](linear_algebra/jacobi_iteration_method.py)
656665
* [Lu Decomposition](linear_algebra/lu_decomposition.py)

bit_manipulation/single_bit_manipulation_operations.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,29 @@ def get_bit(number: int, position: int) -> int:
9494
return int((number & (1 << position)) != 0)
9595

9696

97+
def clear_least_significant_set_bit(number: int) -> int:
98+
"""
99+
Clear the least significant set bit (rightmost 1 bit).
100+
101+
Subtracting 1 changes the rightmost 1 to 0 and the 0 bits to its right to 1.
102+
ANDing the result with the original number therefore clears that set bit.
103+
For negative integers, Python's infinite sign extension is used.
104+
https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
105+
106+
>>> clear_least_significant_set_bit(0b101100) # 0b101000
107+
40
108+
>>> clear_least_significant_set_bit(0b1000) # 0b0
109+
0
110+
>>> clear_least_significant_set_bit(0)
111+
0
112+
>>> clear_least_significant_set_bit(0b1111) # 0b1110
113+
14
114+
>>> clear_least_significant_set_bit(-5)
115+
-6
116+
"""
117+
return number & (number - 1)
118+
119+
97120
if __name__ == "__main__":
98121
import doctest
99122

computer_vision/gramian.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""
2+
Image style reconstruction with Gram matrices.
3+
4+
https://en.wikipedia.org/wiki/Gram_matrix
5+
https://en.wikipedia.org/wiki/Neural_style_transfer
6+
https://arxiv.org/pdf/1603.08155#page=7&zoom=auto,-294,3
7+
"""
8+
9+
import numpy as np
10+
11+
12+
def gram_matrix(mat: np.ndarray) -> np.ndarray:
13+
"""
14+
Returns the Gram (Gramian) matrix of an image.
15+
16+
:param mat: matrix of shape (C, H, W); C = color channels, H = height, W = width.
17+
:type mat: np.ndarray
18+
:return: matrix of shape (C, C).
19+
:rtype: np.ndarray
20+
21+
Examples
22+
--------
23+
>>> gram_matrix(np.ones((2,5,5)))
24+
array([[0.5, 0.5],
25+
[0.5, 0.5]])
26+
>>> gram_matrix(np.ones((3,5,5)))
27+
array([[0.33333333, 0.33333333, 0.33333333],
28+
[0.33333333, 0.33333333, 0.33333333],
29+
[0.33333333, 0.33333333, 0.33333333]])
30+
>>> gram_matrix(np.ones((3,5,5))).shape
31+
(3, 3)
32+
"""
33+
color, height, width = mat.shape
34+
vec = mat.reshape(color, height * width)
35+
gram = vec @ vec.T
36+
return gram / (color * height * width)
37+
38+
39+
def gram_loss(input_features: np.ndarray, reference_features: np.ndarray) -> np.float64:
40+
"""
41+
Calculates the squared Frobenius norm of the difference between
42+
the Gram matrices of the input and reference image.
43+
44+
:param input_features: Feature map of shape (C, H, W)
45+
:type input_features: np.ndarray
46+
:param reference_features: Feature map of shape (C, H, W)
47+
:type reference_features: np.ndarray
48+
:return: Gram loss between the two feature maps.
49+
:rtype: float64
50+
51+
Examples
52+
--------
53+
>>> a = np.random.randn(3,5,5)
54+
>>> gram_loss(a, a)
55+
np.float64(0.0)
56+
>>> a = np.zeros((3,5,5))
57+
>>> b = np.ones((3,5,5))
58+
>>> gram_loss(a, b)
59+
np.float64(1.0)
60+
"""
61+
input_gram = gram_matrix(input_features)
62+
reference_gram = gram_matrix(reference_features)
63+
return np.sum(np.square(input_gram - reference_gram)).astype(np.float64)
64+
65+
66+
if __name__ == "__main__":
67+
import doctest
68+
69+
doctest.testmod()

data_compression/move_to_front.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
"""
2+
Move-to-front transform.
3+
4+
The move-to-front transform encodes each symbol as its current index in an
5+
ordered alphabet, then moves that symbol to the front of the alphabet.
6+
It is commonly used after the Burrows-Wheeler transform in lossless
7+
compression pipelines.
8+
9+
Reference: https://en.wikipedia.org/wiki/Move-to-front_transform
10+
"""
11+
12+
13+
def _validated_alphabet(alphabet: str) -> list[str]:
14+
"""
15+
Return a mutable alphabet list after validating uniqueness.
16+
17+
>>> _validated_alphabet("abc")
18+
['a', 'b', 'c']
19+
>>> _validated_alphabet("aba")
20+
Traceback (most recent call last):
21+
...
22+
ValueError: alphabet must contain unique characters
23+
"""
24+
if not isinstance(alphabet, str):
25+
raise TypeError("alphabet must be a string")
26+
if len(set(alphabet)) != len(alphabet):
27+
raise ValueError("alphabet must contain unique characters")
28+
return list(alphabet)
29+
30+
31+
def move_to_front_encode(text: str, alphabet: str) -> list[int]:
32+
"""
33+
Encode text using the move-to-front transform.
34+
35+
>>> move_to_front_encode("banana", "abcdefghijklmnopqrstuvwxyz")
36+
[1, 1, 13, 1, 1, 1]
37+
>>> move_to_front_encode("banana", "abn")
38+
[1, 1, 2, 1, 1, 1]
39+
>>> move_to_front_encode("", "abc")
40+
[]
41+
>>> move_to_front_encode("bad", "abc")
42+
Traceback (most recent call last):
43+
...
44+
ValueError: character 'd' is not in the alphabet
45+
"""
46+
if not isinstance(text, str):
47+
raise TypeError("text must be a string")
48+
49+
symbols = _validated_alphabet(alphabet)
50+
encoded_text: list[int] = []
51+
52+
for char in text:
53+
try:
54+
char_index = symbols.index(char)
55+
except ValueError:
56+
message = f"character {char!r} is not in the alphabet"
57+
raise ValueError(message) from None
58+
encoded_text.append(char_index)
59+
symbols.insert(0, symbols.pop(char_index))
60+
61+
return encoded_text
62+
63+
64+
def move_to_front_decode(encoded_text: list[int], alphabet: str) -> str:
65+
"""
66+
Decode a move-to-front encoded list of indexes.
67+
68+
>>> move_to_front_decode([1, 1, 13, 1, 1, 1], "abcdefghijklmnopqrstuvwxyz")
69+
'banana'
70+
>>> move_to_front_decode([1, 1, 2, 1, 1, 1], "abn")
71+
'banana'
72+
>>> move_to_front_decode([], "abc")
73+
''
74+
>>> move_to_front_decode([3], "abc")
75+
Traceback (most recent call last):
76+
...
77+
ValueError: index 3 is not valid for alphabet size 3
78+
>>> move_to_front_decode([-1], "abc")
79+
Traceback (most recent call last):
80+
...
81+
ValueError: index -1 is not valid for alphabet size 3
82+
"""
83+
symbols = _validated_alphabet(alphabet)
84+
decoded_text = []
85+
86+
for index in encoded_text:
87+
if not 0 <= index < len(symbols):
88+
message = f"index {index} is not valid for alphabet size {len(symbols)}"
89+
raise ValueError(message)
90+
decoded_text.append(symbols[index])
91+
symbols.insert(0, symbols.pop(index))
92+
93+
return "".join(decoded_text)
94+
95+
96+
if __name__ == "__main__":
97+
import doctest
98+
99+
doctest.testmod()

0 commit comments

Comments
 (0)