mirror of
https://hub.njuu.cf/TheAlgorithms/Python.git
synced 2023-10-11 13:06:12 +08:00
Merge branch 'TheAlgorithms:master' into master
This commit is contained in:
commit
d70575b231
@ -556,7 +556,7 @@
|
||||
* [Bell Numbers](maths/bell_numbers.py)
|
||||
* [Binary Exp Mod](maths/binary_exp_mod.py)
|
||||
* [Binary Exponentiation](maths/binary_exponentiation.py)
|
||||
* [Binary Exponentiation 3](maths/binary_exponentiation_3.py)
|
||||
* [Binary Exponentiation 2](maths/binary_exponentiation_2.py)
|
||||
* [Binary Multiplication](maths/binary_multiplication.py)
|
||||
* [Binomial Coefficient](maths/binomial_coefficient.py)
|
||||
* [Binomial Distribution](maths/binomial_distribution.py)
|
||||
@ -588,7 +588,6 @@
|
||||
* [Find Min](maths/find_min.py)
|
||||
* [Floor](maths/floor.py)
|
||||
* [Gamma](maths/gamma.py)
|
||||
* [Gamma Recursive](maths/gamma_recursive.py)
|
||||
* [Gaussian](maths/gaussian.py)
|
||||
* [Gaussian Error Linear Unit](maths/gaussian_error_linear_unit.py)
|
||||
* [Gcd Of N Numbers](maths/gcd_of_n_numbers.py)
|
||||
@ -723,6 +722,7 @@
|
||||
* Activation Functions
|
||||
* [Exponential Linear Unit](neural_network/activation_functions/exponential_linear_unit.py)
|
||||
* [Leaky Rectified Linear Unit](neural_network/activation_functions/leaky_rectified_linear_unit.py)
|
||||
* [Mish](neural_network/activation_functions/mish.py)
|
||||
* [Rectified Linear Unit](neural_network/activation_functions/rectified_linear_unit.py)
|
||||
* [Scaled Exponential Linear Unit](neural_network/activation_functions/scaled_exponential_linear_unit.py)
|
||||
* [Sigmoid Linear Unit](neural_network/activation_functions/sigmoid_linear_unit.py)
|
||||
@ -748,6 +748,7 @@
|
||||
* [Linear Congruential Generator](other/linear_congruential_generator.py)
|
||||
* [Lru Cache](other/lru_cache.py)
|
||||
* [Magicdiamondpattern](other/magicdiamondpattern.py)
|
||||
* [Majority Vote Algorithm](other/majority_vote_algorithm.py)
|
||||
* [Maximum Subsequence](other/maximum_subsequence.py)
|
||||
* [Nested Brackets](other/nested_brackets.py)
|
||||
* [Number Container System](other/number_container_system.py)
|
||||
@ -1196,7 +1197,6 @@
|
||||
* [Rabin Karp](strings/rabin_karp.py)
|
||||
* [Remove Duplicate](strings/remove_duplicate.py)
|
||||
* [Reverse Letters](strings/reverse_letters.py)
|
||||
* [Reverse Long Words](strings/reverse_long_words.py)
|
||||
* [Reverse Words](strings/reverse_words.py)
|
||||
* [Snake Case To Camel Pascal Case](strings/snake_case_to_camel_pascal_case.py)
|
||||
* [Split](strings/split.py)
|
||||
|
67
bit_manipulation/power_of_4.py
Normal file
67
bit_manipulation/power_of_4.py
Normal file
@ -0,0 +1,67 @@
|
||||
"""
|
||||
|
||||
Task:
|
||||
Given a positive int number. Return True if this number is power of 4
|
||||
or False otherwise.
|
||||
|
||||
Implementation notes: Use bit manipulation.
|
||||
For example if the number is the power of 2 it's bits representation:
|
||||
n = 0..100..00
|
||||
n - 1 = 0..011..11
|
||||
|
||||
n & (n - 1) - no intersections = 0
|
||||
If the number is a power of 4 then it should be a power of 2
|
||||
and the set bit should be at an odd position.
|
||||
"""
|
||||
|
||||
|
||||
def power_of_4(number: int) -> bool:
|
||||
"""
|
||||
Return True if this number is power of 4 or False otherwise.
|
||||
|
||||
>>> power_of_4(0)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: number must be positive
|
||||
>>> power_of_4(1)
|
||||
True
|
||||
>>> power_of_4(2)
|
||||
False
|
||||
>>> power_of_4(4)
|
||||
True
|
||||
>>> power_of_4(6)
|
||||
False
|
||||
>>> power_of_4(8)
|
||||
False
|
||||
>>> power_of_4(17)
|
||||
False
|
||||
>>> power_of_4(64)
|
||||
True
|
||||
>>> power_of_4(-1)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: number must be positive
|
||||
>>> power_of_4(1.2)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: number must be an integer
|
||||
|
||||
"""
|
||||
if not isinstance(number, int):
|
||||
raise TypeError("number must be an integer")
|
||||
if number <= 0:
|
||||
raise ValueError("number must be positive")
|
||||
if number & (number - 1) == 0:
|
||||
c = 0
|
||||
while number:
|
||||
c += 1
|
||||
number >>= 1
|
||||
return c % 2 == 1
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
@ -1,11 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from maths.greatest_common_divisor import greatest_common_divisor
|
||||
|
||||
|
||||
def diophantine(a: int, b: int, c: int) -> tuple[float, float]:
|
||||
"""
|
||||
Diophantine Equation : Given integers a,b,c ( at least one of a and b != 0), the
|
||||
diophantine equation a*x + b*y = c has a solution (where x and y are integers)
|
||||
iff gcd(a,b) divides c.
|
||||
iff greatest_common_divisor(a,b) divides c.
|
||||
|
||||
GCD ( Greatest Common Divisor ) or HCF ( Highest Common Factor )
|
||||
|
||||
@ -22,7 +24,7 @@ def diophantine(a: int, b: int, c: int) -> tuple[float, float]:
|
||||
|
||||
assert (
|
||||
c % greatest_common_divisor(a, b) == 0
|
||||
) # greatest_common_divisor(a,b) function implemented below
|
||||
) # greatest_common_divisor(a,b) is in maths directory
|
||||
(d, x, y) = extended_gcd(a, b) # extended_gcd(a,b) function implemented below
|
||||
r = c / d
|
||||
return (r * x, r * y)
|
||||
@ -69,32 +71,6 @@ def diophantine_all_soln(a: int, b: int, c: int, n: int = 2) -> None:
|
||||
print(x, y)
|
||||
|
||||
|
||||
def greatest_common_divisor(a: int, b: int) -> int:
|
||||
"""
|
||||
Euclid's Lemma : d divides a and b, if and only if d divides a-b and b
|
||||
|
||||
Euclid's Algorithm
|
||||
|
||||
>>> greatest_common_divisor(7,5)
|
||||
1
|
||||
|
||||
Note : In number theory, two integers a and b are said to be relatively prime,
|
||||
mutually prime, or co-prime if the only positive integer (factor) that
|
||||
divides both of them is 1 i.e., gcd(a,b) = 1.
|
||||
|
||||
>>> greatest_common_divisor(121, 11)
|
||||
11
|
||||
|
||||
"""
|
||||
if a < b:
|
||||
a, b = b, a
|
||||
|
||||
while a % b != 0:
|
||||
a, b = b, a % b
|
||||
|
||||
return b
|
||||
|
||||
|
||||
def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
|
||||
"""
|
||||
Extended Euclid's Algorithm : If d divides a and b and d = a*x + b*y for integers
|
||||
|
@ -1,6 +1,8 @@
|
||||
import random
|
||||
import sys
|
||||
|
||||
from maths.greatest_common_divisor import gcd_by_iterative
|
||||
|
||||
from . import cryptomath_module as cryptomath
|
||||
|
||||
SYMBOLS = (
|
||||
@ -26,7 +28,7 @@ def check_keys(key_a: int, key_b: int, mode: str) -> None:
|
||||
"Key A must be greater than 0 and key B must "
|
||||
f"be between 0 and {len(SYMBOLS) - 1}."
|
||||
)
|
||||
if cryptomath.gcd(key_a, len(SYMBOLS)) != 1:
|
||||
if gcd_by_iterative(key_a, len(SYMBOLS)) != 1:
|
||||
sys.exit(
|
||||
f"Key A {key_a} and the symbol set size {len(SYMBOLS)} "
|
||||
"are not relatively prime. Choose a different key."
|
||||
@ -76,7 +78,7 @@ def get_random_key() -> int:
|
||||
while True:
|
||||
key_b = random.randint(2, len(SYMBOLS))
|
||||
key_b = random.randint(2, len(SYMBOLS))
|
||||
if cryptomath.gcd(key_b, len(SYMBOLS)) == 1 and key_b % len(SYMBOLS) != 0:
|
||||
if gcd_by_iterative(key_b, len(SYMBOLS)) == 1 and key_b % len(SYMBOLS) != 0:
|
||||
return key_b * len(SYMBOLS) + key_b
|
||||
|
||||
|
||||
|
@ -1,11 +1,8 @@
|
||||
def gcd(a: int, b: int) -> int:
|
||||
while a != 0:
|
||||
a, b = b % a, a
|
||||
return b
|
||||
from maths.greatest_common_divisor import gcd_by_iterative
|
||||
|
||||
|
||||
def find_mod_inverse(a: int, m: int) -> int:
|
||||
if gcd(a, m) != 1:
|
||||
if gcd_by_iterative(a, m) != 1:
|
||||
msg = f"mod inverse of {a!r} and {m!r} does not exist"
|
||||
raise ValueError(msg)
|
||||
u1, u2, u3 = 1, 0, a
|
||||
|
@ -1,11 +1,28 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def find_primitive(n: int) -> int | None:
|
||||
for r in range(1, n):
|
||||
def find_primitive(modulus: int) -> int | None:
|
||||
"""
|
||||
Find a primitive root modulo modulus, if one exists.
|
||||
|
||||
Args:
|
||||
modulus : The modulus for which to find a primitive root.
|
||||
|
||||
Returns:
|
||||
The primitive root if one exists, or None if there is none.
|
||||
|
||||
Examples:
|
||||
>>> find_primitive(7) # Modulo 7 has primitive root 3
|
||||
3
|
||||
>>> find_primitive(11) # Modulo 11 has primitive root 2
|
||||
2
|
||||
>>> find_primitive(8) == None # Modulo 8 has no primitive root
|
||||
True
|
||||
"""
|
||||
for r in range(1, modulus):
|
||||
li = []
|
||||
for x in range(n - 1):
|
||||
val = pow(r, x, n)
|
||||
for x in range(modulus - 1):
|
||||
val = pow(r, x, modulus)
|
||||
if val in li:
|
||||
break
|
||||
li.append(val)
|
||||
@ -15,18 +32,22 @@ def find_primitive(n: int) -> int | None:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
q = int(input("Enter a prime number q: "))
|
||||
a = find_primitive(q)
|
||||
if a is None:
|
||||
print(f"Cannot find the primitive for the value: {a!r}")
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
|
||||
prime = int(input("Enter a prime number q: "))
|
||||
primitive_root = find_primitive(prime)
|
||||
if primitive_root is None:
|
||||
print(f"Cannot find the primitive for the value: {primitive_root!r}")
|
||||
else:
|
||||
a_private = int(input("Enter private key of A: "))
|
||||
a_public = pow(a, a_private, q)
|
||||
a_public = pow(primitive_root, a_private, prime)
|
||||
b_private = int(input("Enter private key of B: "))
|
||||
b_public = pow(a, b_private, q)
|
||||
b_public = pow(primitive_root, b_private, prime)
|
||||
|
||||
a_secret = pow(b_public, a_private, q)
|
||||
b_secret = pow(a_public, b_private, q)
|
||||
a_secret = pow(b_public, a_private, prime)
|
||||
b_secret = pow(a_public, b_private, prime)
|
||||
|
||||
print("The key value generated by A is: ", a_secret)
|
||||
print("The key value generated by B is: ", b_secret)
|
||||
|
167
ciphers/fractionated_morse_cipher.py
Normal file
167
ciphers/fractionated_morse_cipher.py
Normal file
@ -0,0 +1,167 @@
|
||||
"""
|
||||
Python program for the Fractionated Morse Cipher.
|
||||
|
||||
The Fractionated Morse cipher first converts the plaintext to Morse code,
|
||||
then enciphers fixed-size blocks of Morse code back to letters.
|
||||
This procedure means plaintext letters are mixed into the ciphertext letters,
|
||||
making it more secure than substitution ciphers.
|
||||
|
||||
http://practicalcryptography.com/ciphers/fractionated-morse-cipher/
|
||||
"""
|
||||
import string
|
||||
|
||||
MORSE_CODE_DICT = {
|
||||
"A": ".-",
|
||||
"B": "-...",
|
||||
"C": "-.-.",
|
||||
"D": "-..",
|
||||
"E": ".",
|
||||
"F": "..-.",
|
||||
"G": "--.",
|
||||
"H": "....",
|
||||
"I": "..",
|
||||
"J": ".---",
|
||||
"K": "-.-",
|
||||
"L": ".-..",
|
||||
"M": "--",
|
||||
"N": "-.",
|
||||
"O": "---",
|
||||
"P": ".--.",
|
||||
"Q": "--.-",
|
||||
"R": ".-.",
|
||||
"S": "...",
|
||||
"T": "-",
|
||||
"U": "..-",
|
||||
"V": "...-",
|
||||
"W": ".--",
|
||||
"X": "-..-",
|
||||
"Y": "-.--",
|
||||
"Z": "--..",
|
||||
" ": "",
|
||||
}
|
||||
|
||||
# Define possible trigrams of Morse code
|
||||
MORSE_COMBINATIONS = [
|
||||
"...",
|
||||
"..-",
|
||||
"..x",
|
||||
".-.",
|
||||
".--",
|
||||
".-x",
|
||||
".x.",
|
||||
".x-",
|
||||
".xx",
|
||||
"-..",
|
||||
"-.-",
|
||||
"-.x",
|
||||
"--.",
|
||||
"---",
|
||||
"--x",
|
||||
"-x.",
|
||||
"-x-",
|
||||
"-xx",
|
||||
"x..",
|
||||
"x.-",
|
||||
"x.x",
|
||||
"x-.",
|
||||
"x--",
|
||||
"x-x",
|
||||
"xx.",
|
||||
"xx-",
|
||||
"xxx",
|
||||
]
|
||||
|
||||
# Create a reverse dictionary for Morse code
|
||||
REVERSE_DICT = {value: key for key, value in MORSE_CODE_DICT.items()}
|
||||
|
||||
|
||||
def encode_to_morse(plaintext: str) -> str:
|
||||
"""Encode a plaintext message into Morse code.
|
||||
|
||||
Args:
|
||||
plaintext: The plaintext message to encode.
|
||||
|
||||
Returns:
|
||||
The Morse code representation of the plaintext message.
|
||||
|
||||
Example:
|
||||
>>> encode_to_morse("defend the east")
|
||||
'-..x.x..-.x.x-.x-..xx-x....x.xx.x.-x...x-'
|
||||
"""
|
||||
return "x".join([MORSE_CODE_DICT.get(letter.upper(), "") for letter in plaintext])
|
||||
|
||||
|
||||
def encrypt_fractionated_morse(plaintext: str, key: str) -> str:
|
||||
"""Encrypt a plaintext message using Fractionated Morse Cipher.
|
||||
|
||||
Args:
|
||||
plaintext: The plaintext message to encrypt.
|
||||
key: The encryption key.
|
||||
|
||||
Returns:
|
||||
The encrypted ciphertext.
|
||||
|
||||
Example:
|
||||
>>> encrypt_fractionated_morse("defend the east","Roundtable")
|
||||
'ESOAVVLJRSSTRX'
|
||||
|
||||
"""
|
||||
morse_code = encode_to_morse(plaintext)
|
||||
key = key.upper() + string.ascii_uppercase
|
||||
key = "".join(sorted(set(key), key=key.find))
|
||||
|
||||
# Ensure morse_code length is a multiple of 3
|
||||
padding_length = 3 - (len(morse_code) % 3)
|
||||
morse_code += "x" * padding_length
|
||||
|
||||
fractionated_morse_dict = {v: k for k, v in zip(key, MORSE_COMBINATIONS)}
|
||||
fractionated_morse_dict["xxx"] = ""
|
||||
encrypted_text = "".join(
|
||||
[
|
||||
fractionated_morse_dict[morse_code[i : i + 3]]
|
||||
for i in range(0, len(morse_code), 3)
|
||||
]
|
||||
)
|
||||
return encrypted_text
|
||||
|
||||
|
||||
def decrypt_fractionated_morse(ciphertext: str, key: str) -> str:
|
||||
"""Decrypt a ciphertext message encrypted with Fractionated Morse Cipher.
|
||||
|
||||
Args:
|
||||
ciphertext: The ciphertext message to decrypt.
|
||||
key: The decryption key.
|
||||
|
||||
Returns:
|
||||
The decrypted plaintext message.
|
||||
|
||||
Example:
|
||||
>>> decrypt_fractionated_morse("ESOAVVLJRSSTRX","Roundtable")
|
||||
'DEFEND THE EAST'
|
||||
"""
|
||||
key = key.upper() + string.ascii_uppercase
|
||||
key = "".join(sorted(set(key), key=key.find))
|
||||
|
||||
inverse_fractionated_morse_dict = dict(zip(key, MORSE_COMBINATIONS))
|
||||
morse_code = "".join(
|
||||
[inverse_fractionated_morse_dict.get(letter, "") for letter in ciphertext]
|
||||
)
|
||||
decrypted_text = "".join(
|
||||
[REVERSE_DICT[code] for code in morse_code.split("x")]
|
||||
).strip()
|
||||
return decrypted_text
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
Example usage of Fractionated Morse Cipher.
|
||||
"""
|
||||
plaintext = "defend the east"
|
||||
print("Plain Text:", plaintext)
|
||||
key = "ROUNDTABLE"
|
||||
|
||||
ciphertext = encrypt_fractionated_morse(plaintext, key)
|
||||
print("Encrypted:", ciphertext)
|
||||
|
||||
decrypted_text = decrypt_fractionated_morse(ciphertext, key)
|
||||
print("Decrypted:", decrypted_text)
|
@ -39,19 +39,7 @@ import string
|
||||
|
||||
import numpy
|
||||
|
||||
|
||||
def greatest_common_divisor(a: int, b: int) -> int:
|
||||
"""
|
||||
>>> greatest_common_divisor(4, 8)
|
||||
4
|
||||
>>> greatest_common_divisor(8, 4)
|
||||
4
|
||||
>>> greatest_common_divisor(4, 7)
|
||||
1
|
||||
>>> greatest_common_divisor(0, 10)
|
||||
10
|
||||
"""
|
||||
return b if a == 0 else greatest_common_divisor(b % a, a)
|
||||
from maths.greatest_common_divisor import greatest_common_divisor
|
||||
|
||||
|
||||
class HillCipher:
|
||||
|
@ -2,6 +2,8 @@ import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
from maths.greatest_common_divisor import gcd_by_iterative
|
||||
|
||||
from . import cryptomath_module, rabin_miller
|
||||
|
||||
|
||||
@ -27,7 +29,7 @@ def generate_key(key_size: int) -> tuple[tuple[int, int], tuple[int, int]]:
|
||||
# Generate e that is relatively prime to (p - 1) * (q - 1)
|
||||
while True:
|
||||
e = random.randrange(2 ** (key_size - 1), 2 ** (key_size))
|
||||
if cryptomath_module.gcd(e, (p - 1) * (q - 1)) == 1:
|
||||
if gcd_by_iterative(e, (p - 1) * (q - 1)) == 1:
|
||||
break
|
||||
|
||||
# Calculate d that is mod inverse of e
|
||||
|
59
data_structures/arrays/equilibrium_index_in_array.py
Normal file
59
data_structures/arrays/equilibrium_index_in_array.py
Normal file
@ -0,0 +1,59 @@
|
||||
"""
|
||||
Find the Equilibrium Index of an Array.
|
||||
Reference: https://www.geeksforgeeks.org/equilibrium-index-of-an-array/
|
||||
|
||||
Python doctests can be run with the following command:
|
||||
python -m doctest -v equilibrium_index.py
|
||||
|
||||
Given a sequence arr[] of size n, this function returns
|
||||
an equilibrium index (if any) or -1 if no equilibrium index exists.
|
||||
|
||||
The equilibrium index of an array is an index such that the sum of
|
||||
elements at lower indexes is equal to the sum of elements at higher indexes.
|
||||
|
||||
|
||||
|
||||
Example Input:
|
||||
arr = [-7, 1, 5, 2, -4, 3, 0]
|
||||
Output: 3
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def equilibrium_index(arr: list[int], size: int) -> int:
|
||||
"""
|
||||
Find the equilibrium index of an array.
|
||||
|
||||
Args:
|
||||
arr : The input array of integers.
|
||||
size : The size of the array.
|
||||
|
||||
Returns:
|
||||
int: The equilibrium index or -1 if no equilibrium index exists.
|
||||
|
||||
Examples:
|
||||
>>> equilibrium_index([-7, 1, 5, 2, -4, 3, 0], 7)
|
||||
3
|
||||
>>> equilibrium_index([1, 2, 3, 4, 5], 5)
|
||||
-1
|
||||
>>> equilibrium_index([1, 1, 1, 1, 1], 5)
|
||||
2
|
||||
>>> equilibrium_index([2, 4, 6, 8, 10, 3], 6)
|
||||
-1
|
||||
"""
|
||||
total_sum = sum(arr)
|
||||
left_sum = 0
|
||||
|
||||
for i in range(size):
|
||||
total_sum -= arr[i]
|
||||
if left_sum == total_sum:
|
||||
return i
|
||||
left_sum += arr[i]
|
||||
|
||||
return -1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
@ -1,65 +1,167 @@
|
||||
def is_palindrome(head):
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class ListNode:
|
||||
val: int = 0
|
||||
next_node: ListNode | None = None
|
||||
|
||||
|
||||
def is_palindrome(head: ListNode | None) -> bool:
|
||||
"""
|
||||
Check if a linked list is a palindrome.
|
||||
|
||||
Args:
|
||||
head: The head of the linked list.
|
||||
|
||||
Returns:
|
||||
bool: True if the linked list is a palindrome, False otherwise.
|
||||
|
||||
Examples:
|
||||
>>> is_palindrome(None)
|
||||
True
|
||||
|
||||
>>> is_palindrome(ListNode(1))
|
||||
True
|
||||
|
||||
>>> is_palindrome(ListNode(1, ListNode(2)))
|
||||
False
|
||||
|
||||
>>> is_palindrome(ListNode(1, ListNode(2, ListNode(1))))
|
||||
True
|
||||
|
||||
>>> is_palindrome(ListNode(1, ListNode(2, ListNode(2, ListNode(1)))))
|
||||
True
|
||||
"""
|
||||
if not head:
|
||||
return True
|
||||
# split the list to two parts
|
||||
fast, slow = head.next, head
|
||||
while fast and fast.next:
|
||||
fast = fast.next.next
|
||||
slow = slow.next
|
||||
second = slow.next
|
||||
slow.next = None # Don't forget here! But forget still works!
|
||||
fast: ListNode | None = head.next_node
|
||||
slow: ListNode | None = head
|
||||
while fast and fast.next_node:
|
||||
fast = fast.next_node.next_node
|
||||
slow = slow.next_node if slow else None
|
||||
if slow:
|
||||
# slow will always be defined,
|
||||
# adding this check to resolve mypy static check
|
||||
second = slow.next_node
|
||||
slow.next_node = None # Don't forget here! But forget still works!
|
||||
# reverse the second part
|
||||
node = None
|
||||
node: ListNode | None = None
|
||||
while second:
|
||||
nxt = second.next
|
||||
second.next = node
|
||||
nxt = second.next_node
|
||||
second.next_node = node
|
||||
node = second
|
||||
second = nxt
|
||||
# compare two parts
|
||||
# second part has the same or one less node
|
||||
while node:
|
||||
while node and head:
|
||||
if node.val != head.val:
|
||||
return False
|
||||
node = node.next
|
||||
head = head.next
|
||||
node = node.next_node
|
||||
head = head.next_node
|
||||
return True
|
||||
|
||||
|
||||
def is_palindrome_stack(head):
|
||||
if not head or not head.next:
|
||||
def is_palindrome_stack(head: ListNode | None) -> bool:
|
||||
"""
|
||||
Check if a linked list is a palindrome using a stack.
|
||||
|
||||
Args:
|
||||
head (ListNode): The head of the linked list.
|
||||
|
||||
Returns:
|
||||
bool: True if the linked list is a palindrome, False otherwise.
|
||||
|
||||
Examples:
|
||||
>>> is_palindrome_stack(None)
|
||||
True
|
||||
|
||||
>>> is_palindrome_stack(ListNode(1))
|
||||
True
|
||||
|
||||
>>> is_palindrome_stack(ListNode(1, ListNode(2)))
|
||||
False
|
||||
|
||||
>>> is_palindrome_stack(ListNode(1, ListNode(2, ListNode(1))))
|
||||
True
|
||||
|
||||
>>> is_palindrome_stack(ListNode(1, ListNode(2, ListNode(2, ListNode(1)))))
|
||||
True
|
||||
"""
|
||||
if not head or not head.next_node:
|
||||
return True
|
||||
|
||||
# 1. Get the midpoint (slow)
|
||||
slow = fast = cur = head
|
||||
while fast and fast.next:
|
||||
fast, slow = fast.next.next, slow.next
|
||||
slow: ListNode | None = head
|
||||
fast: ListNode | None = head
|
||||
while fast and fast.next_node:
|
||||
fast = fast.next_node.next_node
|
||||
slow = slow.next_node if slow else None
|
||||
|
||||
# 2. Push the second half into the stack
|
||||
stack = [slow.val]
|
||||
while slow.next:
|
||||
slow = slow.next
|
||||
stack.append(slow.val)
|
||||
# slow will always be defined,
|
||||
# adding this check to resolve mypy static check
|
||||
if slow:
|
||||
stack = [slow.val]
|
||||
|
||||
# 3. Comparison
|
||||
while stack:
|
||||
if stack.pop() != cur.val:
|
||||
return False
|
||||
cur = cur.next
|
||||
# 2. Push the second half into the stack
|
||||
while slow.next_node:
|
||||
slow = slow.next_node
|
||||
stack.append(slow.val)
|
||||
|
||||
# 3. Comparison
|
||||
cur: ListNode | None = head
|
||||
while stack and cur:
|
||||
if stack.pop() != cur.val:
|
||||
return False
|
||||
cur = cur.next_node
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def is_palindrome_dict(head):
|
||||
if not head or not head.next:
|
||||
def is_palindrome_dict(head: ListNode | None) -> bool:
|
||||
"""
|
||||
Check if a linked list is a palindrome using a dictionary.
|
||||
|
||||
Args:
|
||||
head (ListNode): The head of the linked list.
|
||||
|
||||
Returns:
|
||||
bool: True if the linked list is a palindrome, False otherwise.
|
||||
|
||||
Examples:
|
||||
>>> is_palindrome_dict(None)
|
||||
True
|
||||
|
||||
>>> is_palindrome_dict(ListNode(1))
|
||||
True
|
||||
|
||||
>>> is_palindrome_dict(ListNode(1, ListNode(2)))
|
||||
False
|
||||
|
||||
>>> is_palindrome_dict(ListNode(1, ListNode(2, ListNode(1))))
|
||||
True
|
||||
|
||||
>>> is_palindrome_dict(ListNode(1, ListNode(2, ListNode(2, ListNode(1)))))
|
||||
True
|
||||
|
||||
>>> is_palindrome_dict(\
|
||||
ListNode(\
|
||||
1, ListNode(2, ListNode(1, ListNode(3, ListNode(2, ListNode(1)))))))
|
||||
False
|
||||
"""
|
||||
if not head or not head.next_node:
|
||||
return True
|
||||
d = {}
|
||||
d: dict[int, list[int]] = {}
|
||||
pos = 0
|
||||
while head:
|
||||
if head.val in d:
|
||||
d[head.val].append(pos)
|
||||
else:
|
||||
d[head.val] = [pos]
|
||||
head = head.next
|
||||
head = head.next_node
|
||||
pos += 1
|
||||
checksum = pos - 1
|
||||
middle = 0
|
||||
@ -75,3 +177,9 @@ def is_palindrome_dict(head):
|
||||
if middle > 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
|
@ -96,9 +96,16 @@ def test_nearest_neighbour(
|
||||
|
||||
|
||||
def test_local_binary_pattern():
|
||||
file_path = "digital_image_processing/image_data/lena.jpg"
|
||||
# pull request 10161 before:
|
||||
# "digital_image_processing/image_data/lena.jpg"
|
||||
# after: "digital_image_processing/image_data/lena_small.jpg"
|
||||
|
||||
# Reading the image and converting it to grayscale.
|
||||
from os import getenv # Speed up our Continuous Integration tests
|
||||
|
||||
file_name = "lena_small.jpg" if getenv("CI") else "lena.jpg"
|
||||
file_path = f"digital_image_processing/image_data/{file_name}"
|
||||
|
||||
# Reading the image and converting it to grayscale
|
||||
image = imread(file_path, 0)
|
||||
|
||||
# Test for get_neighbors_pixel function() return not None
|
||||
|
42
greedy_methods/best_time_to_buy_and_sell_stock.py
Normal file
42
greedy_methods/best_time_to_buy_and_sell_stock.py
Normal file
@ -0,0 +1,42 @@
|
||||
"""
|
||||
Given a list of stock prices calculate the maximum profit that can be made from a
|
||||
single buy and sell of one share of stock. We only allowed to complete one buy
|
||||
transaction and one sell transaction but must buy before we sell.
|
||||
|
||||
Example : prices = [7, 1, 5, 3, 6, 4]
|
||||
max_profit will return 5 - which is by buying at price 1 and selling at price 6.
|
||||
|
||||
This problem can be solved using the concept of "GREEDY ALGORITHM".
|
||||
|
||||
We iterate over the price array once, keeping track of the lowest price point
|
||||
(buy) and the maximum profit we can get at each point. The greedy choice at each point
|
||||
is to either buy at the current price if it's less than our current buying price, or
|
||||
sell at the current price if the profit is more than our current maximum profit.
|
||||
"""
|
||||
|
||||
|
||||
def max_profit(prices: list[int]) -> int:
|
||||
"""
|
||||
>>> max_profit([7, 1, 5, 3, 6, 4])
|
||||
5
|
||||
>>> max_profit([7, 6, 4, 3, 1])
|
||||
0
|
||||
"""
|
||||
if not prices:
|
||||
return 0
|
||||
|
||||
min_price = prices[0]
|
||||
max_profit: int = 0
|
||||
|
||||
for price in prices:
|
||||
min_price = min(price, min_price)
|
||||
max_profit = max(price - min_price, max_profit)
|
||||
|
||||
return max_profit
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
print(max_profit([7, 1, 5, 3, 6, 4]))
|
59
machine_learning/loss_functions/binary_cross_entropy.py
Normal file
59
machine_learning/loss_functions/binary_cross_entropy.py
Normal file
@ -0,0 +1,59 @@
|
||||
"""
|
||||
Binary Cross-Entropy (BCE) Loss Function
|
||||
|
||||
Description:
|
||||
Quantifies dissimilarity between true labels (0 or 1) and predicted probabilities.
|
||||
It's widely used in binary classification tasks.
|
||||
|
||||
Formula:
|
||||
BCE = -Σ(y_true * log(y_pred) + (1 - y_true) * log(1 - y_pred))
|
||||
|
||||
Source:
|
||||
[Wikipedia - Cross entropy](https://en.wikipedia.org/wiki/Cross_entropy)
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def binary_cross_entropy(
|
||||
y_true: np.ndarray, y_pred: np.ndarray, epsilon: float = 1e-15
|
||||
) -> float:
|
||||
"""
|
||||
Calculate the BCE Loss between true labels and predicted probabilities.
|
||||
|
||||
Parameters:
|
||||
- y_true: True binary labels (0 or 1).
|
||||
- y_pred: Predicted probabilities for class 1.
|
||||
- epsilon: Small constant to avoid numerical instability.
|
||||
|
||||
Returns:
|
||||
- bce_loss: Binary Cross-Entropy Loss.
|
||||
|
||||
Example Usage:
|
||||
>>> true_labels = np.array([0, 1, 1, 0, 1])
|
||||
>>> predicted_probs = np.array([0.2, 0.7, 0.9, 0.3, 0.8])
|
||||
>>> binary_cross_entropy(true_labels, predicted_probs)
|
||||
0.2529995012327421
|
||||
>>> true_labels = np.array([0, 1, 1, 0, 1])
|
||||
>>> predicted_probs = np.array([0.3, 0.8, 0.9, 0.2])
|
||||
>>> binary_cross_entropy(true_labels, predicted_probs)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Input arrays must have the same length.
|
||||
"""
|
||||
if len(y_true) != len(y_pred):
|
||||
raise ValueError("Input arrays must have the same length.")
|
||||
# Clip predicted probabilities to avoid log(0) and log(1)
|
||||
y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
|
||||
|
||||
# Calculate binary cross-entropy loss
|
||||
bce_loss = -(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
|
||||
|
||||
# Take the mean over all samples
|
||||
return np.mean(bce_loss)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
52
machine_learning/loss_functions/huber_loss.py
Normal file
52
machine_learning/loss_functions/huber_loss.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""
|
||||
Huber Loss Function
|
||||
|
||||
Description:
|
||||
Huber loss function describes the penalty incurred by an estimation procedure.
|
||||
It serves as a measure of the model's accuracy in regression tasks.
|
||||
|
||||
Formula:
|
||||
Huber Loss = if |y_true - y_pred| <= delta then 0.5 * (y_true - y_pred)^2
|
||||
else delta * |y_true - y_pred| - 0.5 * delta^2
|
||||
|
||||
Source:
|
||||
[Wikipedia - Huber Loss](https://en.wikipedia.org/wiki/Huber_loss)
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def huber_loss(y_true: np.ndarray, y_pred: np.ndarray, delta: float) -> float:
|
||||
"""
|
||||
Calculate the mean of Huber Loss.
|
||||
|
||||
Parameters:
|
||||
- y_true: The true values (ground truth).
|
||||
- y_pred: The predicted values.
|
||||
|
||||
Returns:
|
||||
- huber_loss: The mean of Huber Loss between y_true and y_pred.
|
||||
|
||||
Example usage:
|
||||
>>> true_values = np.array([0.9, 10.0, 2.0, 1.0, 5.2])
|
||||
>>> predicted_values = np.array([0.8, 2.1, 2.9, 4.2, 5.2])
|
||||
>>> np.isclose(huber_loss(true_values, predicted_values, 1.0), 2.102)
|
||||
True
|
||||
>>> true_labels = np.array([11.0, 21.0, 3.32, 4.0, 5.0])
|
||||
>>> predicted_probs = np.array([8.3, 20.8, 2.9, 11.2, 5.0])
|
||||
>>> np.isclose(huber_loss(true_labels, predicted_probs, 1.0), 1.80164)
|
||||
True
|
||||
"""
|
||||
|
||||
if len(y_true) != len(y_pred):
|
||||
raise ValueError("Input arrays must have the same length.")
|
||||
|
||||
huber_mse = 0.5 * (y_true - y_pred) ** 2
|
||||
huber_mae = delta * (np.abs(y_true - y_pred) - 0.5 * delta)
|
||||
return np.where(np.abs(y_true - y_pred) <= delta, huber_mse, huber_mae).mean()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
51
machine_learning/loss_functions/mean_squared_error.py
Normal file
51
machine_learning/loss_functions/mean_squared_error.py
Normal file
@ -0,0 +1,51 @@
|
||||
"""
|
||||
Mean Squared Error (MSE) Loss Function
|
||||
|
||||
Description:
|
||||
MSE measures the mean squared difference between true values and predicted values.
|
||||
It serves as a measure of the model's accuracy in regression tasks.
|
||||
|
||||
Formula:
|
||||
MSE = (1/n) * Σ(y_true - y_pred)^2
|
||||
|
||||
Source:
|
||||
[Wikipedia - Mean squared error](https://en.wikipedia.org/wiki/Mean_squared_error)
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def mean_squared_error(y_true: np.ndarray, y_pred: np.ndarray) -> float:
|
||||
"""
|
||||
Calculate the Mean Squared Error (MSE) between two arrays.
|
||||
|
||||
Parameters:
|
||||
- y_true: The true values (ground truth).
|
||||
- y_pred: The predicted values.
|
||||
|
||||
Returns:
|
||||
- mse: The Mean Squared Error between y_true and y_pred.
|
||||
|
||||
Example usage:
|
||||
>>> true_values = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
|
||||
>>> predicted_values = np.array([0.8, 2.1, 2.9, 4.2, 5.2])
|
||||
>>> mean_squared_error(true_values, predicted_values)
|
||||
0.028000000000000032
|
||||
>>> true_labels = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
|
||||
>>> predicted_probs = np.array([0.3, 0.8, 0.9, 0.2])
|
||||
>>> mean_squared_error(true_labels, predicted_probs)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Input arrays must have the same length.
|
||||
"""
|
||||
if len(y_true) != len(y_pred):
|
||||
raise ValueError("Input arrays must have the same length.")
|
||||
|
||||
squared_errors = (y_true - y_pred) ** 2
|
||||
return np.mean(squared_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
@ -10,14 +10,7 @@ satisfies the following modular arithmetic condition:
|
||||
Examples of Carmichael Numbers: 561, 1105, ...
|
||||
https://en.wikipedia.org/wiki/Carmichael_number
|
||||
"""
|
||||
|
||||
|
||||
def gcd(a: int, b: int) -> int:
|
||||
if a < b:
|
||||
return gcd(b, a)
|
||||
if a % b == 0:
|
||||
return b
|
||||
return gcd(b, a % b)
|
||||
from maths.greatest_common_divisor import greatest_common_divisor
|
||||
|
||||
|
||||
def power(x: int, y: int, mod: int) -> int:
|
||||
@ -33,7 +26,7 @@ def power(x: int, y: int, mod: int) -> int:
|
||||
def is_carmichael_number(n: int) -> bool:
|
||||
b = 2
|
||||
while b < n:
|
||||
if gcd(b, n) == 1 and power(b, n - 1, n) != 1:
|
||||
if greatest_common_divisor(b, n) == 1 and power(b, n - 1, n) != 1:
|
||||
return False
|
||||
b += 1
|
||||
return True
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""
|
||||
https://en.wikipedia.org/wiki/Combination
|
||||
"""
|
||||
from math import factorial
|
||||
|
||||
|
||||
def combinations(n: int, k: int) -> int:
|
||||
@ -35,7 +34,11 @@ def combinations(n: int, k: int) -> int:
|
||||
# to calculate a factorial of a negative number, which is not possible
|
||||
if n < k or k < 0:
|
||||
raise ValueError("Please enter positive integers for n and k where n >= k")
|
||||
return factorial(n) // (factorial(k) * factorial(n - k))
|
||||
res = 1
|
||||
for i in range(k):
|
||||
res *= n - i
|
||||
res //= i + 1
|
||||
return res
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
72
maths/germain_primes.py
Normal file
72
maths/germain_primes.py
Normal file
@ -0,0 +1,72 @@
|
||||
"""
|
||||
A Sophie Germain prime is any prime p, where 2p + 1 is also prime.
|
||||
The second number, 2p + 1 is called a safe prime.
|
||||
|
||||
Examples of Germain primes include: 2, 3, 5, 11, 23
|
||||
|
||||
Their corresponding safe primes: 5, 7, 11, 23, 47
|
||||
https://en.wikipedia.org/wiki/Safe_and_Sophie_Germain_primes
|
||||
"""
|
||||
|
||||
from maths.prime_check import is_prime
|
||||
|
||||
|
||||
def is_germain_prime(number: int) -> bool:
|
||||
"""Checks if input number and 2*number + 1 are prime.
|
||||
|
||||
>>> is_germain_prime(3)
|
||||
True
|
||||
>>> is_germain_prime(11)
|
||||
True
|
||||
>>> is_germain_prime(4)
|
||||
False
|
||||
>>> is_germain_prime(23)
|
||||
True
|
||||
>>> is_germain_prime(13)
|
||||
False
|
||||
>>> is_germain_prime(20)
|
||||
False
|
||||
>>> is_germain_prime('abc')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Input value must be a positive integer. Input value: abc
|
||||
"""
|
||||
if not isinstance(number, int) or number < 1:
|
||||
msg = f"Input value must be a positive integer. Input value: {number}"
|
||||
raise TypeError(msg)
|
||||
|
||||
return is_prime(number) and is_prime(2 * number + 1)
|
||||
|
||||
|
||||
def is_safe_prime(number: int) -> bool:
|
||||
"""Checks if input number and (number - 1)/2 are prime.
|
||||
The smallest safe prime is 5, with the Germain prime is 2.
|
||||
|
||||
>>> is_safe_prime(5)
|
||||
True
|
||||
>>> is_safe_prime(11)
|
||||
True
|
||||
>>> is_safe_prime(1)
|
||||
False
|
||||
>>> is_safe_prime(2)
|
||||
False
|
||||
>>> is_safe_prime(3)
|
||||
False
|
||||
>>> is_safe_prime(47)
|
||||
True
|
||||
>>> is_safe_prime('abc')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Input value must be a positive integer. Input value: abc
|
||||
"""
|
||||
if not isinstance(number, int) or number < 1:
|
||||
msg = f"Input value must be a positive integer. Input value: {number}"
|
||||
raise TypeError(msg)
|
||||
|
||||
return (number - 1) % 2 == 0 and is_prime(number) and is_prime((number - 1) // 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from doctest import testmod
|
||||
|
||||
testmod()
|
@ -1,6 +1,8 @@
|
||||
import unittest
|
||||
from timeit import timeit
|
||||
|
||||
from maths.greatest_common_divisor import greatest_common_divisor
|
||||
|
||||
|
||||
def least_common_multiple_slow(first_num: int, second_num: int) -> int:
|
||||
"""
|
||||
@ -20,26 +22,6 @@ def least_common_multiple_slow(first_num: int, second_num: int) -> int:
|
||||
return common_mult
|
||||
|
||||
|
||||
def greatest_common_divisor(a: int, b: int) -> int:
|
||||
"""
|
||||
Calculate Greatest Common Divisor (GCD).
|
||||
see greatest_common_divisor.py
|
||||
>>> greatest_common_divisor(24, 40)
|
||||
8
|
||||
>>> greatest_common_divisor(1, 1)
|
||||
1
|
||||
>>> greatest_common_divisor(1, 800)
|
||||
1
|
||||
>>> greatest_common_divisor(11, 37)
|
||||
1
|
||||
>>> greatest_common_divisor(3, 5)
|
||||
1
|
||||
>>> greatest_common_divisor(16, 4)
|
||||
4
|
||||
"""
|
||||
return b if a == 0 else greatest_common_divisor(b % a, a)
|
||||
|
||||
|
||||
def least_common_multiple_fast(first_num: int, second_num: int) -> int:
|
||||
"""
|
||||
Find the least common multiple of two numbers.
|
||||
|
@ -21,7 +21,6 @@ get_primes_between(pNumber1, pNumber2)
|
||||
|
||||
is_even(number)
|
||||
is_odd(number)
|
||||
gcd(number1, number2) // greatest common divisor
|
||||
kg_v(number1, number2) // least common multiple
|
||||
get_divisors(number) // all divisors of 'number' inclusive 1, number
|
||||
is_perfect_number(number)
|
||||
@ -40,6 +39,8 @@ goldbach(number) // Goldbach's assumption
|
||||
|
||||
from math import sqrt
|
||||
|
||||
from maths.greatest_common_divisor import gcd_by_iterative
|
||||
|
||||
|
||||
def is_prime(number: int) -> bool:
|
||||
"""
|
||||
@ -317,39 +318,6 @@ def goldbach(number):
|
||||
# ----------------------------------------------
|
||||
|
||||
|
||||
def gcd(number1, number2):
|
||||
"""
|
||||
Greatest common divisor
|
||||
input: two positive integer 'number1' and 'number2'
|
||||
returns the greatest common divisor of 'number1' and 'number2'
|
||||
"""
|
||||
|
||||
# precondition
|
||||
assert (
|
||||
isinstance(number1, int)
|
||||
and isinstance(number2, int)
|
||||
and (number1 >= 0)
|
||||
and (number2 >= 0)
|
||||
), "'number1' and 'number2' must been positive integer."
|
||||
|
||||
rest = 0
|
||||
|
||||
while number2 != 0:
|
||||
rest = number1 % number2
|
||||
number1 = number2
|
||||
number2 = rest
|
||||
|
||||
# precondition
|
||||
assert isinstance(number1, int) and (
|
||||
number1 >= 0
|
||||
), "'number' must been from type int and positive"
|
||||
|
||||
return number1
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
|
||||
|
||||
def kg_v(number1, number2):
|
||||
"""
|
||||
Least common multiple
|
||||
@ -567,14 +535,14 @@ def simplify_fraction(numerator, denominator):
|
||||
), "The arguments must been from type int and 'denominator' != 0"
|
||||
|
||||
# build the greatest common divisor of numerator and denominator.
|
||||
gcd_of_fraction = gcd(abs(numerator), abs(denominator))
|
||||
gcd_of_fraction = gcd_by_iterative(abs(numerator), abs(denominator))
|
||||
|
||||
# precondition
|
||||
assert (
|
||||
isinstance(gcd_of_fraction, int)
|
||||
and (numerator % gcd_of_fraction == 0)
|
||||
and (denominator % gcd_of_fraction == 0)
|
||||
), "Error in function gcd(...,...)"
|
||||
), "Error in function gcd_by_iterative(...,...)"
|
||||
|
||||
return (numerator // gcd_of_fraction, denominator // gcd_of_fraction)
|
||||
|
||||
|
36
neural_network/activation_functions/binary_step.py
Normal file
36
neural_network/activation_functions/binary_step.py
Normal file
@ -0,0 +1,36 @@
|
||||
"""
|
||||
This script demonstrates the implementation of the Binary Step function.
|
||||
|
||||
It's an activation function in which the neuron is activated if the input is positive
|
||||
or 0, else it is deactivated
|
||||
|
||||
It's a simple activation function which is mentioned in this wikipedia article:
|
||||
https://en.wikipedia.org/wiki/Activation_function
|
||||
"""
|
||||
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def binary_step(vector: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
Implements the binary step function
|
||||
|
||||
Parameters:
|
||||
vector (ndarray): A vector that consists of numeric values
|
||||
|
||||
Returns:
|
||||
vector (ndarray): Input vector after applying binary step function
|
||||
|
||||
>>> vector = np.array([-1.2, 0, 2, 1.45, -3.7, 0.3])
|
||||
>>> binary_step(vector)
|
||||
array([0, 1, 1, 1, 0, 1])
|
||||
"""
|
||||
|
||||
return np.where(vector >= 0, 1, 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
@ -7,6 +7,7 @@ https://en.wikipedia.org/wiki/Rectifier_(neural_networks)#Mish
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from softplus import softplus
|
||||
|
||||
|
||||
def mish(vector: np.ndarray) -> np.ndarray:
|
||||
@ -30,7 +31,7 @@ def mish(vector: np.ndarray) -> np.ndarray:
|
||||
array([-0.00092952, -0.15113318, 0.33152014, -0.04745745])
|
||||
|
||||
"""
|
||||
return vector * np.tanh(np.log(1 + np.exp(vector)))
|
||||
return vector * np.tanh(softplus(vector))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -0,0 +1,49 @@
|
||||
"""
|
||||
This script implements the Soboleva Modified Hyperbolic Tangent function.
|
||||
|
||||
The function applies the Soboleva Modified Hyperbolic Tangent function
|
||||
to each element of the vector.
|
||||
|
||||
More details about the activation function can be found on:
|
||||
https://en.wikipedia.org/wiki/Soboleva_modified_hyperbolic_tangent
|
||||
"""
|
||||
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def soboleva_modified_hyperbolic_tangent(
|
||||
vector: np.ndarray, a_value: float, b_value: float, c_value: float, d_value: float
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
Implements the Soboleva Modified Hyperbolic Tangent function
|
||||
|
||||
Parameters:
|
||||
vector (ndarray): A vector that consists of numeric values
|
||||
a_value (float): parameter a of the equation
|
||||
b_value (float): parameter b of the equation
|
||||
c_value (float): parameter c of the equation
|
||||
d_value (float): parameter d of the equation
|
||||
|
||||
Returns:
|
||||
vector (ndarray): Input array after applying SMHT function
|
||||
|
||||
>>> vector = np.array([5.4, -2.4, 6.3, -5.23, 3.27, 0.56])
|
||||
>>> soboleva_modified_hyperbolic_tangent(vector, 0.2, 0.4, 0.6, 0.8)
|
||||
array([ 0.11075085, -0.28236685, 0.07861169, -0.1180085 , 0.22999056,
|
||||
0.1566043 ])
|
||||
"""
|
||||
|
||||
# Separate the numerator and denominator for simplicity
|
||||
# Calculate the numerator and denominator element-wise
|
||||
numerator = np.exp(a_value * vector) - np.exp(-b_value * vector)
|
||||
denominator = np.exp(c_value * vector) + np.exp(-d_value * vector)
|
||||
|
||||
# Calculate and return the final result element-wise
|
||||
return numerator / denominator
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
38
neural_network/activation_functions/squareplus.py
Normal file
38
neural_network/activation_functions/squareplus.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""
|
||||
Squareplus Activation Function
|
||||
|
||||
Use Case: Squareplus designed to enhance positive values and suppress negative values.
|
||||
For more detailed information, you can refer to the following link:
|
||||
https://en.wikipedia.org/wiki/Rectifier_(neural_networks)#Squareplus
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def squareplus(vector: np.ndarray, beta: float) -> np.ndarray:
|
||||
"""
|
||||
Implements the SquarePlus activation function.
|
||||
|
||||
Parameters:
|
||||
vector (np.ndarray): The input array for the SquarePlus activation.
|
||||
beta (float): size of the curved region
|
||||
|
||||
Returns:
|
||||
np.ndarray: The input array after applying the SquarePlus activation.
|
||||
|
||||
Formula: f(x) = ( x + sqrt(x^2 + b) ) / 2
|
||||
|
||||
Examples:
|
||||
>>> squareplus(np.array([2.3, 0.6, -2, -3.8]), beta=2)
|
||||
array([2.5 , 1.06811457, 0.22474487, 0.12731349])
|
||||
|
||||
>>> squareplus(np.array([-9.2, -0.3, 0.45, -4.56]), beta=3)
|
||||
array([0.0808119 , 0.72891979, 1.11977651, 0.15893419])
|
||||
"""
|
||||
return (vector + np.sqrt(vector**2 + beta)) / 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
@ -4,52 +4,76 @@
|
||||
# Function to print upper half of diamond (pyramid)
|
||||
def floyd(n):
|
||||
"""
|
||||
Parameters:
|
||||
n : size of pattern
|
||||
Print the upper half of a diamond pattern with '*' characters.
|
||||
|
||||
Args:
|
||||
n (int): Size of the pattern.
|
||||
|
||||
Examples:
|
||||
>>> floyd(3)
|
||||
' * \\n * * \\n* * * \\n'
|
||||
|
||||
>>> floyd(5)
|
||||
' * \\n * * \\n * * * \\n * * * * \\n* * * * * \\n'
|
||||
"""
|
||||
result = ""
|
||||
for i in range(n):
|
||||
for _ in range(n - i - 1): # printing spaces
|
||||
print(" ", end="")
|
||||
result += " "
|
||||
for _ in range(i + 1): # printing stars
|
||||
print("* ", end="")
|
||||
print()
|
||||
result += "* "
|
||||
result += "\n"
|
||||
return result
|
||||
|
||||
|
||||
# Function to print lower half of diamond (pyramid)
|
||||
def reverse_floyd(n):
|
||||
"""
|
||||
Parameters:
|
||||
n : size of pattern
|
||||
Print the lower half of a diamond pattern with '*' characters.
|
||||
|
||||
Args:
|
||||
n (int): Size of the pattern.
|
||||
|
||||
Examples:
|
||||
>>> reverse_floyd(3)
|
||||
'* * * \\n * * \\n * \\n '
|
||||
|
||||
>>> reverse_floyd(5)
|
||||
'* * * * * \\n * * * * \\n * * * \\n * * \\n * \\n '
|
||||
"""
|
||||
result = ""
|
||||
for i in range(n, 0, -1):
|
||||
for _ in range(i, 0, -1): # printing stars
|
||||
print("* ", end="")
|
||||
print()
|
||||
result += "* "
|
||||
result += "\n"
|
||||
for _ in range(n - i + 1, 0, -1): # printing spaces
|
||||
print(" ", end="")
|
||||
result += " "
|
||||
return result
|
||||
|
||||
|
||||
# Function to print complete diamond pattern of "*"
|
||||
def pretty_print(n):
|
||||
"""
|
||||
Parameters:
|
||||
n : size of pattern
|
||||
Print a complete diamond pattern with '*' characters.
|
||||
|
||||
Args:
|
||||
n (int): Size of the pattern.
|
||||
|
||||
Examples:
|
||||
>>> pretty_print(0)
|
||||
' ... .... nothing printing :('
|
||||
|
||||
>>> pretty_print(3)
|
||||
' * \\n * * \\n* * * \\n* * * \\n * * \\n * \\n '
|
||||
"""
|
||||
if n <= 0:
|
||||
print(" ... .... nothing printing :(")
|
||||
return
|
||||
floyd(n) # upper half
|
||||
reverse_floyd(n) # lower half
|
||||
return " ... .... nothing printing :("
|
||||
upper_half = floyd(n) # upper half
|
||||
lower_half = reverse_floyd(n) # lower half
|
||||
return upper_half + lower_half
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(r"| /\ | |- | |- |--| |\ /| |-")
|
||||
print(r"|/ \| |- |_ |_ |__| | \/ | |_")
|
||||
K = 1
|
||||
while K:
|
||||
user_number = int(input("enter the number and , and see the magic : "))
|
||||
print()
|
||||
pretty_print(user_number)
|
||||
K = int(input("press 0 to exit... and 1 to continue..."))
|
||||
import doctest
|
||||
|
||||
print("Good Bye...")
|
||||
doctest.testmod()
|
||||
|
@ -1,3 +1,5 @@
|
||||
from maths.greatest_common_divisor import greatest_common_divisor
|
||||
|
||||
"""
|
||||
Project Euler Problem 5: https://projecteuler.net/problem=5
|
||||
|
||||
@ -16,23 +18,6 @@ References:
|
||||
"""
|
||||
|
||||
|
||||
def greatest_common_divisor(x: int, y: int) -> int:
|
||||
"""
|
||||
Euclidean Greatest Common Divisor algorithm
|
||||
|
||||
>>> greatest_common_divisor(0, 0)
|
||||
0
|
||||
>>> greatest_common_divisor(23, 42)
|
||||
1
|
||||
>>> greatest_common_divisor(15, 33)
|
||||
3
|
||||
>>> greatest_common_divisor(12345, 67890)
|
||||
15
|
||||
"""
|
||||
|
||||
return x if y == 0 else greatest_common_divisor(y, x % y)
|
||||
|
||||
|
||||
def lcm(x: int, y: int) -> int:
|
||||
"""
|
||||
Least Common Multiple.
|
||||
|
107
searches/median_of_medians.py
Normal file
107
searches/median_of_medians.py
Normal file
@ -0,0 +1,107 @@
|
||||
"""
|
||||
A Python implementation of the Median of Medians algorithm
|
||||
to select pivots for quick_select, which is efficient for
|
||||
calculating the value that would appear in the index of a
|
||||
list if it would be sorted, even if it is not already
|
||||
sorted. Search in time complexity O(n) at any rank
|
||||
deterministically
|
||||
https://en.wikipedia.org/wiki/Median_of_medians
|
||||
"""
|
||||
|
||||
|
||||
def median_of_five(arr: list) -> int:
|
||||
"""
|
||||
Return the median of the input list
|
||||
:param arr: Array to find median of
|
||||
:return: median of arr
|
||||
|
||||
>>> median_of_five([2, 4, 5, 7, 899])
|
||||
5
|
||||
>>> median_of_five([5, 7, 899, 54, 32])
|
||||
32
|
||||
>>> median_of_five([5, 4, 3, 2])
|
||||
4
|
||||
>>> median_of_five([3, 5, 7, 10, 2])
|
||||
5
|
||||
"""
|
||||
arr = sorted(arr)
|
||||
return arr[len(arr) // 2]
|
||||
|
||||
|
||||
def median_of_medians(arr: list) -> int:
|
||||
"""
|
||||
Return a pivot to partition data on by calculating
|
||||
Median of medians of input data
|
||||
:param arr: The data to be checked (a list)
|
||||
:return: median of medians of input array
|
||||
|
||||
>>> median_of_medians([2, 4, 5, 7, 899, 54, 32])
|
||||
54
|
||||
>>> median_of_medians([5, 7, 899, 54, 32])
|
||||
32
|
||||
>>> median_of_medians([5, 4, 3, 2])
|
||||
4
|
||||
>>> median_of_medians([3, 5, 7, 10, 2, 12])
|
||||
12
|
||||
"""
|
||||
|
||||
if len(arr) <= 5:
|
||||
return median_of_five(arr)
|
||||
medians = []
|
||||
i = 0
|
||||
while i < len(arr):
|
||||
if (i + 4) <= len(arr):
|
||||
medians.append(median_of_five(arr[i:].copy()))
|
||||
else:
|
||||
medians.append(median_of_five(arr[i : i + 5].copy()))
|
||||
i += 5
|
||||
return median_of_medians(medians)
|
||||
|
||||
|
||||
def quick_select(arr: list, target: int) -> int:
|
||||
"""
|
||||
Two way partition the data into smaller and greater lists,
|
||||
in relationship to the pivot
|
||||
:param arr: The data to be searched (a list)
|
||||
:param target: The rank to be searched
|
||||
:return: element at rank target
|
||||
|
||||
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 5)
|
||||
32
|
||||
>>> quick_select([2, 4, 5, 7, 899, 54, 32], 1)
|
||||
2
|
||||
>>> quick_select([5, 4, 3, 2], 2)
|
||||
3
|
||||
>>> quick_select([3, 5, 7, 10, 2, 12], 3)
|
||||
5
|
||||
"""
|
||||
|
||||
# Invalid Input
|
||||
if target > len(arr):
|
||||
return -1
|
||||
|
||||
# x is the estimated pivot by median of medians algorithm
|
||||
x = median_of_medians(arr)
|
||||
left = []
|
||||
right = []
|
||||
check = False
|
||||
for i in range(len(arr)):
|
||||
if arr[i] < x:
|
||||
left.append(arr[i])
|
||||
elif arr[i] > x:
|
||||
right.append(arr[i])
|
||||
elif arr[i] == x and not check:
|
||||
check = True
|
||||
else:
|
||||
right.append(arr[i])
|
||||
rank_x = len(left) + 1
|
||||
if rank_x == target:
|
||||
answer = x
|
||||
elif rank_x > target:
|
||||
answer = quick_select(left, target)
|
||||
elif rank_x < target:
|
||||
answer = quick_select(right, target - rank_x)
|
||||
return answer
|
||||
|
||||
|
||||
print(median_of_five([5, 4, 3, 2]))
|
@ -1,19 +1,24 @@
|
||||
def reverse_letters(input_str: str) -> str:
|
||||
def reverse_letters(sentence: str, length: int = 0) -> str:
|
||||
"""
|
||||
Reverses letters in a given string without adjusting the position of the words
|
||||
>>> reverse_letters('The cat in the hat')
|
||||
'ehT tac ni eht tah'
|
||||
>>> reverse_letters('The quick brown fox jumped over the lazy dog.')
|
||||
'ehT kciuq nworb xof depmuj revo eht yzal .god'
|
||||
>>> reverse_letters('Is this true?')
|
||||
'sI siht ?eurt'
|
||||
>>> reverse_letters("I love Python")
|
||||
'I evol nohtyP'
|
||||
Reverse all words that are longer than the given length of characters in a sentence.
|
||||
If unspecified, length is taken as 0
|
||||
|
||||
>>> reverse_letters("Hey wollef sroirraw", 3)
|
||||
'Hey fellow warriors'
|
||||
>>> reverse_letters("nohtyP is nohtyP", 2)
|
||||
'Python is Python'
|
||||
>>> reverse_letters("1 12 123 1234 54321 654321", 0)
|
||||
'1 21 321 4321 12345 123456'
|
||||
>>> reverse_letters("racecar")
|
||||
'racecar'
|
||||
"""
|
||||
return " ".join([word[::-1] for word in input_str.split()])
|
||||
return " ".join(
|
||||
"".join(word[::-1]) if len(word) > length else word for word in sentence.split()
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
print(reverse_letters("Hey wollef sroirraw"))
|
||||
|
@ -1,21 +0,0 @@
|
||||
def reverse_long_words(sentence: str) -> str:
|
||||
"""
|
||||
Reverse all words that are longer than 4 characters in a sentence.
|
||||
|
||||
>>> reverse_long_words("Hey wollef sroirraw")
|
||||
'Hey fellow warriors'
|
||||
>>> reverse_long_words("nohtyP is nohtyP")
|
||||
'Python is Python'
|
||||
>>> reverse_long_words("1 12 123 1234 54321 654321")
|
||||
'1 12 123 1234 12345 123456'
|
||||
"""
|
||||
return " ".join(
|
||||
"".join(word[::-1]) if len(word) > 4 else word for word in sentence.split()
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
print(reverse_long_words("Hey wollef sroirraw"))
|
33
strings/strip.py
Normal file
33
strings/strip.py
Normal file
@ -0,0 +1,33 @@
|
||||
def strip(user_string: str, characters: str = " \t\n\r") -> str:
|
||||
"""
|
||||
Remove leading and trailing characters (whitespace by default) from a string.
|
||||
|
||||
Args:
|
||||
user_string (str): The input string to be stripped.
|
||||
characters (str, optional): Optional characters to be removed
|
||||
(default is whitespace).
|
||||
|
||||
Returns:
|
||||
str: The stripped string.
|
||||
|
||||
Examples:
|
||||
>>> strip(" hello ")
|
||||
'hello'
|
||||
>>> strip("...world...", ".")
|
||||
'world'
|
||||
>>> strip("123hello123", "123")
|
||||
'hello'
|
||||
>>> strip("")
|
||||
''
|
||||
"""
|
||||
|
||||
start = 0
|
||||
end = len(user_string)
|
||||
|
||||
while start < end and user_string[start] in characters:
|
||||
start += 1
|
||||
|
||||
while end > start and user_string[end - 1] in characters:
|
||||
end -= 1
|
||||
|
||||
return user_string[start:end]
|
Loading…
Reference in New Issue
Block a user