mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-02-25 18:38:39 +00:00
Compare commits
No commits in common. "0fd0adeae95c1e1f1c94d82061b473bbe8a0c904" and "be44d46bd8456bb0ae5c1342662cd1a69a5e72e6" have entirely different histories.
0fd0adeae9
...
be44d46bd8
@ -1,8 +0,0 @@
|
|||||||
# https://github.com/microsoft/vscode-dev-containers/blob/main/containers/python-3/README.md
|
|
||||||
ARG VARIANT=3.11-bookworm
|
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/python:${VARIANT}
|
|
||||||
COPY requirements.txt /tmp/pip-tmp/
|
|
||||||
RUN python3 -m pip install --upgrade pip \
|
|
||||||
&& python3 -m pip install --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
|
|
||||||
&& pipx install pre-commit ruff \
|
|
||||||
&& pre-commit install
|
|
@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Python 3",
|
|
||||||
"build": {
|
|
||||||
"dockerfile": "Dockerfile",
|
|
||||||
"context": "..",
|
|
||||||
"args": {
|
|
||||||
// Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6
|
|
||||||
// Append -bullseye or -buster to pin to an OS version.
|
|
||||||
// Use -bullseye variants on local on arm64/Apple Silicon.
|
|
||||||
"VARIANT": "3.11-bookworm",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Configure tool-specific properties.
|
|
||||||
"customizations": {
|
|
||||||
// Configure properties specific to VS Code.
|
|
||||||
"vscode": {
|
|
||||||
// Set *default* container specific settings.json values on container create.
|
|
||||||
"settings": {
|
|
||||||
"python.defaultInterpreterPath": "/usr/local/bin/python",
|
|
||||||
"python.linting.enabled": true,
|
|
||||||
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
|
||||||
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy"
|
|
||||||
},
|
|
||||||
|
|
||||||
// Add the IDs of extensions you want installed when the container is created.
|
|
||||||
"extensions": [
|
|
||||||
"ms-python.python",
|
|
||||||
"ms-python.vscode-pylance"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
||||||
// "forwardPorts": [],
|
|
||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
|
||||||
// "postCreateCommand": "pip3 install --user -r requirements.txt",
|
|
||||||
|
|
||||||
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
|
||||||
"remoteUser": "vscode"
|
|
||||||
}
|
|
@ -16,7 +16,7 @@ repos:
|
|||||||
- id: auto-walrus
|
- id: auto-walrus
|
||||||
|
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.0.284
|
rev: v0.0.280
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ repos:
|
|||||||
- tomli
|
- tomli
|
||||||
|
|
||||||
- repo: https://github.com/tox-dev/pyproject-fmt
|
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||||
rev: "0.13.1"
|
rev: "0.13.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyproject-fmt
|
- id: pyproject-fmt
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ repos:
|
|||||||
- id: validate-pyproject
|
- id: validate-pyproject
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.5.0
|
rev: v1.4.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
args:
|
args:
|
||||||
|
15
DIRECTORY.md
15
DIRECTORY.md
@ -74,7 +74,6 @@
|
|||||||
* [Game Of Life](cellular_automata/game_of_life.py)
|
* [Game Of Life](cellular_automata/game_of_life.py)
|
||||||
* [Nagel Schrekenberg](cellular_automata/nagel_schrekenberg.py)
|
* [Nagel Schrekenberg](cellular_automata/nagel_schrekenberg.py)
|
||||||
* [One Dimensional](cellular_automata/one_dimensional.py)
|
* [One Dimensional](cellular_automata/one_dimensional.py)
|
||||||
* [Wa Tor](cellular_automata/wa_tor.py)
|
|
||||||
|
|
||||||
## Ciphers
|
## Ciphers
|
||||||
* [A1Z26](ciphers/a1z26.py)
|
* [A1Z26](ciphers/a1z26.py)
|
||||||
@ -237,8 +236,8 @@
|
|||||||
* [Double Ended Queue](data_structures/queue/double_ended_queue.py)
|
* [Double Ended Queue](data_structures/queue/double_ended_queue.py)
|
||||||
* [Linked Queue](data_structures/queue/linked_queue.py)
|
* [Linked Queue](data_structures/queue/linked_queue.py)
|
||||||
* [Priority Queue Using List](data_structures/queue/priority_queue_using_list.py)
|
* [Priority Queue Using List](data_structures/queue/priority_queue_using_list.py)
|
||||||
* [Queue By List](data_structures/queue/queue_by_list.py)
|
|
||||||
* [Queue By Two Stacks](data_structures/queue/queue_by_two_stacks.py)
|
* [Queue By Two Stacks](data_structures/queue/queue_by_two_stacks.py)
|
||||||
|
* [Queue On List](data_structures/queue/queue_on_list.py)
|
||||||
* [Queue On Pseudo Stack](data_structures/queue/queue_on_pseudo_stack.py)
|
* [Queue On Pseudo Stack](data_structures/queue/queue_on_pseudo_stack.py)
|
||||||
* Stacks
|
* Stacks
|
||||||
* [Balanced Parentheses](data_structures/stacks/balanced_parentheses.py)
|
* [Balanced Parentheses](data_structures/stacks/balanced_parentheses.py)
|
||||||
@ -336,11 +335,9 @@
|
|||||||
* [Minimum Tickets Cost](dynamic_programming/minimum_tickets_cost.py)
|
* [Minimum Tickets Cost](dynamic_programming/minimum_tickets_cost.py)
|
||||||
* [Optimal Binary Search Tree](dynamic_programming/optimal_binary_search_tree.py)
|
* [Optimal Binary Search Tree](dynamic_programming/optimal_binary_search_tree.py)
|
||||||
* [Palindrome Partitioning](dynamic_programming/palindrome_partitioning.py)
|
* [Palindrome Partitioning](dynamic_programming/palindrome_partitioning.py)
|
||||||
* [Regex Match](dynamic_programming/regex_match.py)
|
|
||||||
* [Rod Cutting](dynamic_programming/rod_cutting.py)
|
* [Rod Cutting](dynamic_programming/rod_cutting.py)
|
||||||
* [Subset Generation](dynamic_programming/subset_generation.py)
|
* [Subset Generation](dynamic_programming/subset_generation.py)
|
||||||
* [Sum Of Subset](dynamic_programming/sum_of_subset.py)
|
* [Sum Of Subset](dynamic_programming/sum_of_subset.py)
|
||||||
* [Tribonacci](dynamic_programming/tribonacci.py)
|
|
||||||
* [Viterbi](dynamic_programming/viterbi.py)
|
* [Viterbi](dynamic_programming/viterbi.py)
|
||||||
* [Word Break](dynamic_programming/word_break.py)
|
* [Word Break](dynamic_programming/word_break.py)
|
||||||
|
|
||||||
@ -514,7 +511,7 @@
|
|||||||
* Lstm
|
* Lstm
|
||||||
* [Lstm Prediction](machine_learning/lstm/lstm_prediction.py)
|
* [Lstm Prediction](machine_learning/lstm/lstm_prediction.py)
|
||||||
* [Multilayer Perceptron Classifier](machine_learning/multilayer_perceptron_classifier.py)
|
* [Multilayer Perceptron Classifier](machine_learning/multilayer_perceptron_classifier.py)
|
||||||
* [Polynomial Regression](machine_learning/polynomial_regression.py)
|
* [Polymonial Regression](machine_learning/polymonial_regression.py)
|
||||||
* [Scoring Functions](machine_learning/scoring_functions.py)
|
* [Scoring Functions](machine_learning/scoring_functions.py)
|
||||||
* [Self Organizing Map](machine_learning/self_organizing_map.py)
|
* [Self Organizing Map](machine_learning/self_organizing_map.py)
|
||||||
* [Sequential Minimum Optimization](machine_learning/sequential_minimum_optimization.py)
|
* [Sequential Minimum Optimization](machine_learning/sequential_minimum_optimization.py)
|
||||||
@ -573,7 +570,9 @@
|
|||||||
* [Fermat Little Theorem](maths/fermat_little_theorem.py)
|
* [Fermat Little Theorem](maths/fermat_little_theorem.py)
|
||||||
* [Fibonacci](maths/fibonacci.py)
|
* [Fibonacci](maths/fibonacci.py)
|
||||||
* [Find Max](maths/find_max.py)
|
* [Find Max](maths/find_max.py)
|
||||||
|
* [Find Max Recursion](maths/find_max_recursion.py)
|
||||||
* [Find Min](maths/find_min.py)
|
* [Find Min](maths/find_min.py)
|
||||||
|
* [Find Min Recursion](maths/find_min_recursion.py)
|
||||||
* [Floor](maths/floor.py)
|
* [Floor](maths/floor.py)
|
||||||
* [Gamma](maths/gamma.py)
|
* [Gamma](maths/gamma.py)
|
||||||
* [Gamma Recursive](maths/gamma_recursive.py)
|
* [Gamma Recursive](maths/gamma_recursive.py)
|
||||||
@ -586,7 +585,6 @@
|
|||||||
* [Hardy Ramanujanalgo](maths/hardy_ramanujanalgo.py)
|
* [Hardy Ramanujanalgo](maths/hardy_ramanujanalgo.py)
|
||||||
* [Hexagonal Number](maths/hexagonal_number.py)
|
* [Hexagonal Number](maths/hexagonal_number.py)
|
||||||
* [Integration By Simpson Approx](maths/integration_by_simpson_approx.py)
|
* [Integration By Simpson Approx](maths/integration_by_simpson_approx.py)
|
||||||
* [Interquartile Range](maths/interquartile_range.py)
|
|
||||||
* [Is Int Palindrome](maths/is_int_palindrome.py)
|
* [Is Int Palindrome](maths/is_int_palindrome.py)
|
||||||
* [Is Ip V4 Address Valid](maths/is_ip_v4_address_valid.py)
|
* [Is Ip V4 Address Valid](maths/is_ip_v4_address_valid.py)
|
||||||
* [Is Square Free](maths/is_square_free.py)
|
* [Is Square Free](maths/is_square_free.py)
|
||||||
@ -711,6 +709,7 @@
|
|||||||
* [Exponential Linear Unit](neural_network/activation_functions/exponential_linear_unit.py)
|
* [Exponential Linear Unit](neural_network/activation_functions/exponential_linear_unit.py)
|
||||||
* [Back Propagation Neural Network](neural_network/back_propagation_neural_network.py)
|
* [Back Propagation Neural Network](neural_network/back_propagation_neural_network.py)
|
||||||
* [Convolution Neural Network](neural_network/convolution_neural_network.py)
|
* [Convolution Neural Network](neural_network/convolution_neural_network.py)
|
||||||
|
* [Input Data](neural_network/input_data.py)
|
||||||
* [Perceptron](neural_network/perceptron.py)
|
* [Perceptron](neural_network/perceptron.py)
|
||||||
* [Simple Neural Network](neural_network/simple_neural_network.py)
|
* [Simple Neural Network](neural_network/simple_neural_network.py)
|
||||||
|
|
||||||
@ -741,9 +740,7 @@
|
|||||||
* [Tower Of Hanoi](other/tower_of_hanoi.py)
|
* [Tower Of Hanoi](other/tower_of_hanoi.py)
|
||||||
|
|
||||||
## Physics
|
## Physics
|
||||||
* [Altitude Pressure](physics/altitude_pressure.py)
|
|
||||||
* [Archimedes Principle](physics/archimedes_principle.py)
|
* [Archimedes Principle](physics/archimedes_principle.py)
|
||||||
* [Basic Orbital Capture](physics/basic_orbital_capture.py)
|
|
||||||
* [Casimir Effect](physics/casimir_effect.py)
|
* [Casimir Effect](physics/casimir_effect.py)
|
||||||
* [Centripetal Force](physics/centripetal_force.py)
|
* [Centripetal Force](physics/centripetal_force.py)
|
||||||
* [Grahams Law](physics/grahams_law.py)
|
* [Grahams Law](physics/grahams_law.py)
|
||||||
@ -1065,6 +1062,7 @@
|
|||||||
* [Q Fourier Transform](quantum/q_fourier_transform.py)
|
* [Q Fourier Transform](quantum/q_fourier_transform.py)
|
||||||
* [Q Full Adder](quantum/q_full_adder.py)
|
* [Q Full Adder](quantum/q_full_adder.py)
|
||||||
* [Quantum Entanglement](quantum/quantum_entanglement.py)
|
* [Quantum Entanglement](quantum/quantum_entanglement.py)
|
||||||
|
* [Quantum Random](quantum/quantum_random.py)
|
||||||
* [Quantum Teleportation](quantum/quantum_teleportation.py)
|
* [Quantum Teleportation](quantum/quantum_teleportation.py)
|
||||||
* [Ripple Adder Classic](quantum/ripple_adder_classic.py)
|
* [Ripple Adder Classic](quantum/ripple_adder_classic.py)
|
||||||
* [Single Qubit Measure](quantum/single_qubit_measure.py)
|
* [Single Qubit Measure](quantum/single_qubit_measure.py)
|
||||||
@ -1170,7 +1168,6 @@
|
|||||||
* [Is Pangram](strings/is_pangram.py)
|
* [Is Pangram](strings/is_pangram.py)
|
||||||
* [Is Spain National Id](strings/is_spain_national_id.py)
|
* [Is Spain National Id](strings/is_spain_national_id.py)
|
||||||
* [Is Srilankan Phone Number](strings/is_srilankan_phone_number.py)
|
* [Is Srilankan Phone Number](strings/is_srilankan_phone_number.py)
|
||||||
* [Is Valid Email Address](strings/is_valid_email_address.py)
|
|
||||||
* [Jaro Winkler](strings/jaro_winkler.py)
|
* [Jaro Winkler](strings/jaro_winkler.py)
|
||||||
* [Join](strings/join.py)
|
* [Join](strings/join.py)
|
||||||
* [Knuth Morris Pratt](strings/knuth_morris_pratt.py)
|
* [Knuth Morris Pratt](strings/knuth_morris_pratt.py)
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<img src="https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square" height="20" alt="Contributions Welcome">
|
<img src="https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square" height="20" alt="Contributions Welcome">
|
||||||
</a>
|
</a>
|
||||||
<img src="https://img.shields.io/github/repo-size/TheAlgorithms/Python.svg?label=Repo%20size&style=flat-square" height="20">
|
<img src="https://img.shields.io/github/repo-size/TheAlgorithms/Python.svg?label=Repo%20size&style=flat-square" height="20">
|
||||||
<a href="https://the-algorithms.com/discord">
|
<a href="https://discord.gg/c7MnfGFGa6">
|
||||||
<img src="https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square" height="20" alt="Discord chat">
|
<img src="https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square" height="20" alt="Discord chat">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://gitter.im/TheAlgorithms/community">
|
<a href="https://gitter.im/TheAlgorithms/community">
|
||||||
@ -42,7 +42,7 @@ Read through our [Contribution Guidelines](CONTRIBUTING.md) before you contribut
|
|||||||
|
|
||||||
## Community Channels
|
## Community Channels
|
||||||
|
|
||||||
We are on [Discord](https://the-algorithms.com/discord) and [Gitter](https://gitter.im/TheAlgorithms/community)! Community channels are a great way for you to ask questions and get help. Please join us!
|
We are on [Discord](https://discord.gg/c7MnfGFGa6) and [Gitter](https://gitter.im/TheAlgorithms/community)! Community channels are a great way for you to ask questions and get help. Please join us!
|
||||||
|
|
||||||
## List of Algorithms
|
## List of Algorithms
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ Python:
|
|||||||
- 3.5
|
- 3.5
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
- $python3 game_of_life <canvas_size:int>
|
- $python3 game_o_life <canvas_size:int>
|
||||||
|
|
||||||
Game-Of-Life Rules:
|
Game-Of-Life Rules:
|
||||||
|
|
||||||
@ -52,8 +52,7 @@ def seed(canvas: list[list[bool]]) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def run(canvas: list[list[bool]]) -> list[list[bool]]:
|
def run(canvas: list[list[bool]]) -> list[list[bool]]:
|
||||||
"""
|
"""This function runs the rules of game through all points, and changes their
|
||||||
This function runs the rules of game through all points, and changes their
|
|
||||||
status accordingly.(in the same canvas)
|
status accordingly.(in the same canvas)
|
||||||
@Args:
|
@Args:
|
||||||
--
|
--
|
||||||
@ -61,7 +60,7 @@ def run(canvas: list[list[bool]]) -> list[list[bool]]:
|
|||||||
|
|
||||||
@returns:
|
@returns:
|
||||||
--
|
--
|
||||||
canvas of population after one step
|
None
|
||||||
"""
|
"""
|
||||||
current_canvas = np.array(canvas)
|
current_canvas = np.array(canvas)
|
||||||
next_gen_canvas = np.array(create_canvas(current_canvas.shape[0]))
|
next_gen_canvas = np.array(create_canvas(current_canvas.shape[0]))
|
||||||
@ -71,7 +70,10 @@ def run(canvas: list[list[bool]]) -> list[list[bool]]:
|
|||||||
pt, current_canvas[r - 1 : r + 2, c - 1 : c + 2]
|
pt, current_canvas[r - 1 : r + 2, c - 1 : c + 2]
|
||||||
)
|
)
|
||||||
|
|
||||||
return next_gen_canvas.tolist()
|
current_canvas = next_gen_canvas
|
||||||
|
del next_gen_canvas # cleaning memory as we move on.
|
||||||
|
return_canvas: list[list[bool]] = current_canvas.tolist()
|
||||||
|
return return_canvas
|
||||||
|
|
||||||
|
|
||||||
def __judge_point(pt: bool, neighbours: list[list[bool]]) -> bool:
|
def __judge_point(pt: bool, neighbours: list[list[bool]]) -> bool:
|
||||||
|
@ -1,550 +0,0 @@
|
|||||||
"""
|
|
||||||
Wa-Tor algorithm (1984)
|
|
||||||
|
|
||||||
@ https://en.wikipedia.org/wiki/Wa-Tor
|
|
||||||
@ https://beltoforion.de/en/wator/
|
|
||||||
@ https://beltoforion.de/en/wator/images/wator_medium.webm
|
|
||||||
|
|
||||||
This solution aims to completely remove any systematic approach
|
|
||||||
to the Wa-Tor planet, and utilise fully random methods.
|
|
||||||
|
|
||||||
The constants are a working set that allows the Wa-Tor planet
|
|
||||||
to result in one of the three possible results.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from collections.abc import Callable
|
|
||||||
from random import randint, shuffle
|
|
||||||
from time import sleep
|
|
||||||
from typing import Literal
|
|
||||||
|
|
||||||
WIDTH = 50 # Width of the Wa-Tor planet
|
|
||||||
HEIGHT = 50 # Height of the Wa-Tor planet
|
|
||||||
|
|
||||||
PREY_INITIAL_COUNT = 30 # The initial number of prey entities
|
|
||||||
PREY_REPRODUCTION_TIME = 5 # The chronons before reproducing
|
|
||||||
|
|
||||||
PREDATOR_INITIAL_COUNT = 50 # The initial number of predator entities
|
|
||||||
# The initial energy value of predator entities
|
|
||||||
PREDATOR_INITIAL_ENERGY_VALUE = 15
|
|
||||||
# The energy value provided when consuming prey
|
|
||||||
PREDATOR_FOOD_VALUE = 5
|
|
||||||
PREDATOR_REPRODUCTION_TIME = 20 # The chronons before reproducing
|
|
||||||
|
|
||||||
MAX_ENTITIES = 500 # The max number of organisms on the board
|
|
||||||
# The number of entities to delete from the unbalanced side
|
|
||||||
DELETE_UNBALANCED_ENTITIES = 50
|
|
||||||
|
|
||||||
|
|
||||||
class Entity:
|
|
||||||
"""
|
|
||||||
Represents an entity (either prey or predator).
|
|
||||||
|
|
||||||
>>> e = Entity(True, coords=(0, 0))
|
|
||||||
>>> e.prey
|
|
||||||
True
|
|
||||||
>>> e.coords
|
|
||||||
(0, 0)
|
|
||||||
>>> e.alive
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, prey: bool, coords: tuple[int, int]) -> None:
|
|
||||||
self.prey = prey
|
|
||||||
# The (row, col) pos of the entity
|
|
||||||
self.coords = coords
|
|
||||||
|
|
||||||
self.remaining_reproduction_time = (
|
|
||||||
PREY_REPRODUCTION_TIME if prey else PREDATOR_REPRODUCTION_TIME
|
|
||||||
)
|
|
||||||
self.energy_value = None if prey is True else PREDATOR_INITIAL_ENERGY_VALUE
|
|
||||||
self.alive = True
|
|
||||||
|
|
||||||
def reset_reproduction_time(self) -> None:
|
|
||||||
"""
|
|
||||||
>>> e = Entity(True, coords=(0, 0))
|
|
||||||
>>> e.reset_reproduction_time()
|
|
||||||
>>> e.remaining_reproduction_time == PREY_REPRODUCTION_TIME
|
|
||||||
True
|
|
||||||
>>> e = Entity(False, coords=(0, 0))
|
|
||||||
>>> e.reset_reproduction_time()
|
|
||||||
>>> e.remaining_reproduction_time == PREDATOR_REPRODUCTION_TIME
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
self.remaining_reproduction_time = (
|
|
||||||
PREY_REPRODUCTION_TIME if self.prey is True else PREDATOR_REPRODUCTION_TIME
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
"""
|
|
||||||
>>> Entity(prey=True, coords=(1, 1))
|
|
||||||
Entity(prey=True, coords=(1, 1), remaining_reproduction_time=5)
|
|
||||||
>>> Entity(prey=False, coords=(2, 1)) # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
Entity(prey=False, coords=(2, 1),
|
|
||||||
remaining_reproduction_time=20, energy_value=15)
|
|
||||||
"""
|
|
||||||
repr_ = (
|
|
||||||
f"Entity(prey={self.prey}, coords={self.coords}, "
|
|
||||||
f"remaining_reproduction_time={self.remaining_reproduction_time}"
|
|
||||||
)
|
|
||||||
if self.energy_value is not None:
|
|
||||||
repr_ += f", energy_value={self.energy_value}"
|
|
||||||
return f"{repr_})"
|
|
||||||
|
|
||||||
|
|
||||||
class WaTor:
|
|
||||||
"""
|
|
||||||
Represents the main Wa-Tor algorithm.
|
|
||||||
|
|
||||||
:attr time_passed: A function that is called every time
|
|
||||||
time passes (a chronon) in order to visually display
|
|
||||||
the new Wa-Tor planet. The time_passed function can block
|
|
||||||
using time.sleep to slow the algorithm progression.
|
|
||||||
|
|
||||||
>>> wt = WaTor(10, 15)
|
|
||||||
>>> wt.width
|
|
||||||
10
|
|
||||||
>>> wt.height
|
|
||||||
15
|
|
||||||
>>> len(wt.planet)
|
|
||||||
15
|
|
||||||
>>> len(wt.planet[0])
|
|
||||||
10
|
|
||||||
>>> len(wt.get_entities()) == PREDATOR_INITIAL_COUNT + PREY_INITIAL_COUNT
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
|
|
||||||
time_passed: Callable[["WaTor", int], None] | None
|
|
||||||
|
|
||||||
def __init__(self, width: int, height: int) -> None:
|
|
||||||
self.width = width
|
|
||||||
self.height = height
|
|
||||||
self.time_passed = None
|
|
||||||
|
|
||||||
self.planet: list[list[Entity | None]] = [[None] * width for _ in range(height)]
|
|
||||||
|
|
||||||
# Populate planet with predators and prey randomly
|
|
||||||
for _ in range(PREY_INITIAL_COUNT):
|
|
||||||
self.add_entity(prey=True)
|
|
||||||
for _ in range(PREDATOR_INITIAL_COUNT):
|
|
||||||
self.add_entity(prey=False)
|
|
||||||
self.set_planet(self.planet)
|
|
||||||
|
|
||||||
def set_planet(self, planet: list[list[Entity | None]]) -> None:
|
|
||||||
"""
|
|
||||||
Ease of access for testing
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> planet = [
|
|
||||||
... [None, None, None],
|
|
||||||
... [None, Entity(True, coords=(1, 1)), None]
|
|
||||||
... ]
|
|
||||||
>>> wt.set_planet(planet)
|
|
||||||
>>> wt.planet == planet
|
|
||||||
True
|
|
||||||
>>> wt.width
|
|
||||||
3
|
|
||||||
>>> wt.height
|
|
||||||
2
|
|
||||||
"""
|
|
||||||
self.planet = planet
|
|
||||||
self.width = len(planet[0])
|
|
||||||
self.height = len(planet)
|
|
||||||
|
|
||||||
def add_entity(self, prey: bool) -> None:
|
|
||||||
"""
|
|
||||||
Adds an entity, making sure the entity does
|
|
||||||
not override another entity
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> wt.set_planet([[None, None], [None, None]])
|
|
||||||
>>> wt.add_entity(True)
|
|
||||||
>>> len(wt.get_entities())
|
|
||||||
1
|
|
||||||
>>> wt.add_entity(False)
|
|
||||||
>>> len(wt.get_entities())
|
|
||||||
2
|
|
||||||
"""
|
|
||||||
while True:
|
|
||||||
row, col = randint(0, self.height - 1), randint(0, self.width - 1)
|
|
||||||
if self.planet[row][col] is None:
|
|
||||||
self.planet[row][col] = Entity(prey=prey, coords=(row, col))
|
|
||||||
return
|
|
||||||
|
|
||||||
def get_entities(self) -> list[Entity]:
|
|
||||||
"""
|
|
||||||
Returns a list of all the entities within the planet.
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> len(wt.get_entities()) == PREDATOR_INITIAL_COUNT + PREY_INITIAL_COUNT
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
return [entity for column in self.planet for entity in column if entity]
|
|
||||||
|
|
||||||
def balance_predators_and_prey(self) -> None:
|
|
||||||
"""
|
|
||||||
Balances predators and preys so that prey
|
|
||||||
can not dominate the predators, blocking up
|
|
||||||
space for them to reproduce.
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> for i in range(2000):
|
|
||||||
... row, col = i // HEIGHT, i % WIDTH
|
|
||||||
... wt.planet[row][col] = Entity(True, coords=(row, col))
|
|
||||||
>>> entities = len(wt.get_entities())
|
|
||||||
>>> wt.balance_predators_and_prey()
|
|
||||||
>>> len(wt.get_entities()) == entities
|
|
||||||
False
|
|
||||||
"""
|
|
||||||
entities = self.get_entities()
|
|
||||||
shuffle(entities)
|
|
||||||
|
|
||||||
if len(entities) >= MAX_ENTITIES - MAX_ENTITIES / 10:
|
|
||||||
prey = [entity for entity in entities if entity.prey]
|
|
||||||
predators = [entity for entity in entities if not entity.prey]
|
|
||||||
|
|
||||||
prey_count, predator_count = len(prey), len(predators)
|
|
||||||
|
|
||||||
entities_to_purge = (
|
|
||||||
prey[:DELETE_UNBALANCED_ENTITIES]
|
|
||||||
if prey_count > predator_count
|
|
||||||
else predators[:DELETE_UNBALANCED_ENTITIES]
|
|
||||||
)
|
|
||||||
for entity in entities_to_purge:
|
|
||||||
self.planet[entity.coords[0]][entity.coords[1]] = None
|
|
||||||
|
|
||||||
def get_surrounding_prey(self, entity: Entity) -> list[Entity]:
|
|
||||||
"""
|
|
||||||
Returns all the prey entities around (N, S, E, W) a predator entity.
|
|
||||||
|
|
||||||
Subtly different to the try_to_move_to_unoccupied square.
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> wt.set_planet([
|
|
||||||
... [None, Entity(True, (0, 1)), None],
|
|
||||||
... [None, Entity(False, (1, 1)), None],
|
|
||||||
... [None, Entity(True, (2, 1)), None]])
|
|
||||||
>>> wt.get_surrounding_prey(
|
|
||||||
... Entity(False, (1, 1))) # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
[Entity(prey=True, coords=(0, 1), remaining_reproduction_time=5),
|
|
||||||
Entity(prey=True, coords=(2, 1), remaining_reproduction_time=5)]
|
|
||||||
>>> wt.set_planet([[Entity(False, (0, 0))]])
|
|
||||||
>>> wt.get_surrounding_prey(Entity(False, (0, 0)))
|
|
||||||
[]
|
|
||||||
>>> wt.set_planet([
|
|
||||||
... [Entity(True, (0, 0)), Entity(False, (1, 0)), Entity(False, (2, 0))],
|
|
||||||
... [None, Entity(False, (1, 1)), Entity(True, (2, 1))],
|
|
||||||
... [None, None, None]])
|
|
||||||
>>> wt.get_surrounding_prey(Entity(False, (1, 0)))
|
|
||||||
[Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5)]
|
|
||||||
"""
|
|
||||||
row, col = entity.coords
|
|
||||||
adjacent: list[tuple[int, int]] = [
|
|
||||||
(row - 1, col), # North
|
|
||||||
(row + 1, col), # South
|
|
||||||
(row, col - 1), # West
|
|
||||||
(row, col + 1), # East
|
|
||||||
]
|
|
||||||
|
|
||||||
return [
|
|
||||||
ent
|
|
||||||
for r, c in adjacent
|
|
||||||
if 0 <= r < self.height
|
|
||||||
and 0 <= c < self.width
|
|
||||||
and (ent := self.planet[r][c]) is not None
|
|
||||||
and ent.prey
|
|
||||||
]
|
|
||||||
|
|
||||||
def move_and_reproduce(
|
|
||||||
self, entity: Entity, direction_orders: list[Literal["N", "E", "S", "W"]]
|
|
||||||
) -> None:
|
|
||||||
"""
|
|
||||||
Attempts to move to an unoccupied neighbouring square
|
|
||||||
in either of the four directions (North, South, East, West).
|
|
||||||
If the move was successful and the remaining_reproduction time is
|
|
||||||
equal to 0, then a new prey or predator can also be created
|
|
||||||
in the previous square.
|
|
||||||
|
|
||||||
:param direction_orders: Ordered list (like priority queue) depicting
|
|
||||||
order to attempt to move. Removes any systematic
|
|
||||||
approach of checking neighbouring squares.
|
|
||||||
|
|
||||||
>>> planet = [
|
|
||||||
... [None, None, None],
|
|
||||||
... [None, Entity(True, coords=(1, 1)), None],
|
|
||||||
... [None, None, None]
|
|
||||||
... ]
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> wt.set_planet(planet)
|
|
||||||
>>> wt.move_and_reproduce(Entity(True, coords=(1, 1)), direction_orders=["N"])
|
|
||||||
>>> wt.planet # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
[[None, Entity(prey=True, coords=(0, 1), remaining_reproduction_time=4), None],
|
|
||||||
[None, None, None],
|
|
||||||
[None, None, None]]
|
|
||||||
>>> wt.planet[0][0] = Entity(True, coords=(0, 0))
|
|
||||||
>>> wt.move_and_reproduce(Entity(True, coords=(0, 1)),
|
|
||||||
... direction_orders=["N", "W", "E", "S"])
|
|
||||||
>>> wt.planet # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
[[Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5), None,
|
|
||||||
Entity(prey=True, coords=(0, 2), remaining_reproduction_time=4)],
|
|
||||||
[None, None, None],
|
|
||||||
[None, None, None]]
|
|
||||||
>>> wt.planet[0][1] = wt.planet[0][2]
|
|
||||||
>>> wt.planet[0][2] = None
|
|
||||||
>>> wt.move_and_reproduce(Entity(True, coords=(0, 1)),
|
|
||||||
... direction_orders=["N", "W", "S", "E"])
|
|
||||||
>>> wt.planet # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
[[Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5), None, None],
|
|
||||||
[None, Entity(prey=True, coords=(1, 1), remaining_reproduction_time=4), None],
|
|
||||||
[None, None, None]]
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> reproducable_entity = Entity(False, coords=(0, 1))
|
|
||||||
>>> reproducable_entity.remaining_reproduction_time = 0
|
|
||||||
>>> wt.planet = [[None, reproducable_entity]]
|
|
||||||
>>> wt.move_and_reproduce(reproducable_entity,
|
|
||||||
... direction_orders=["N", "W", "S", "E"])
|
|
||||||
>>> wt.planet # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
[[Entity(prey=False, coords=(0, 0),
|
|
||||||
remaining_reproduction_time=20, energy_value=15),
|
|
||||||
Entity(prey=False, coords=(0, 1), remaining_reproduction_time=20,
|
|
||||||
energy_value=15)]]
|
|
||||||
"""
|
|
||||||
row, col = coords = entity.coords
|
|
||||||
|
|
||||||
adjacent_squares: dict[Literal["N", "E", "S", "W"], tuple[int, int]] = {
|
|
||||||
"N": (row - 1, col), # North
|
|
||||||
"S": (row + 1, col), # South
|
|
||||||
"W": (row, col - 1), # West
|
|
||||||
"E": (row, col + 1), # East
|
|
||||||
}
|
|
||||||
# Weight adjacent locations
|
|
||||||
adjacent: list[tuple[int, int]] = []
|
|
||||||
for order in direction_orders:
|
|
||||||
adjacent.append(adjacent_squares[order])
|
|
||||||
|
|
||||||
for r, c in adjacent:
|
|
||||||
if (
|
|
||||||
0 <= r < self.height
|
|
||||||
and 0 <= c < self.width
|
|
||||||
and self.planet[r][c] is None
|
|
||||||
):
|
|
||||||
# Move entity to empty adjacent square
|
|
||||||
self.planet[r][c] = entity
|
|
||||||
self.planet[row][col] = None
|
|
||||||
entity.coords = (r, c)
|
|
||||||
break
|
|
||||||
|
|
||||||
# (2.) See if it possible to reproduce in previous square
|
|
||||||
if coords != entity.coords and entity.remaining_reproduction_time <= 0:
|
|
||||||
# Check if the entities on the planet is less than the max limit
|
|
||||||
if len(self.get_entities()) < MAX_ENTITIES:
|
|
||||||
# Reproduce in previous square
|
|
||||||
self.planet[row][col] = Entity(prey=entity.prey, coords=coords)
|
|
||||||
entity.reset_reproduction_time()
|
|
||||||
else:
|
|
||||||
entity.remaining_reproduction_time -= 1
|
|
||||||
|
|
||||||
def perform_prey_actions(
|
|
||||||
self, entity: Entity, direction_orders: list[Literal["N", "E", "S", "W"]]
|
|
||||||
) -> None:
|
|
||||||
"""
|
|
||||||
Performs the actions for a prey entity
|
|
||||||
|
|
||||||
For prey the rules are:
|
|
||||||
1. At each chronon, a prey moves randomly to one of the adjacent unoccupied
|
|
||||||
squares. If there are no free squares, no movement takes place.
|
|
||||||
2. Once a prey has survived a certain number of chronons it may reproduce.
|
|
||||||
This is done as it moves to a neighbouring square,
|
|
||||||
leaving behind a new prey in its old position.
|
|
||||||
Its reproduction time is also reset to zero.
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> reproducable_entity = Entity(True, coords=(0, 1))
|
|
||||||
>>> reproducable_entity.remaining_reproduction_time = 0
|
|
||||||
>>> wt.planet = [[None, reproducable_entity]]
|
|
||||||
>>> wt.perform_prey_actions(reproducable_entity,
|
|
||||||
... direction_orders=["N", "W", "S", "E"])
|
|
||||||
>>> wt.planet # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
[[Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5),
|
|
||||||
Entity(prey=True, coords=(0, 1), remaining_reproduction_time=5)]]
|
|
||||||
"""
|
|
||||||
self.move_and_reproduce(entity, direction_orders)
|
|
||||||
|
|
||||||
def perform_predator_actions(
|
|
||||||
self,
|
|
||||||
entity: Entity,
|
|
||||||
occupied_by_prey_coords: tuple[int, int] | None,
|
|
||||||
direction_orders: list[Literal["N", "E", "S", "W"]],
|
|
||||||
) -> None:
|
|
||||||
"""
|
|
||||||
Performs the actions for a predator entity
|
|
||||||
|
|
||||||
:param occupied_by_prey_coords: Move to this location if there is prey there
|
|
||||||
|
|
||||||
For predators the rules are:
|
|
||||||
1. At each chronon, a predator moves randomly to an adjacent square occupied
|
|
||||||
by a prey. If there is none, the predator moves to a random adjacent
|
|
||||||
unoccupied square. If there are no free squares, no movement takes place.
|
|
||||||
2. At each chronon, each predator is deprived of a unit of energy.
|
|
||||||
3. Upon reaching zero energy, a predator dies.
|
|
||||||
4. If a predator moves to a square occupied by a prey,
|
|
||||||
it eats the prey and earns a certain amount of energy.
|
|
||||||
5. Once a predator has survived a certain number of chronons
|
|
||||||
it may reproduce in exactly the same way as the prey.
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> wt.set_planet([[Entity(True, coords=(0, 0)), Entity(False, coords=(0, 1))]])
|
|
||||||
>>> wt.perform_predator_actions(Entity(False, coords=(0, 1)), (0, 0), [])
|
|
||||||
>>> wt.planet # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
[[Entity(prey=False, coords=(0, 0),
|
|
||||||
remaining_reproduction_time=20, energy_value=19), None]]
|
|
||||||
"""
|
|
||||||
assert entity.energy_value is not None # [type checking]
|
|
||||||
|
|
||||||
# (3.) If the entity has 0 energy, it will die
|
|
||||||
if entity.energy_value == 0:
|
|
||||||
self.planet[entity.coords[0]][entity.coords[1]] = None
|
|
||||||
return
|
|
||||||
|
|
||||||
# (1.) Move to entity if possible
|
|
||||||
if occupied_by_prey_coords is not None:
|
|
||||||
# Kill the prey
|
|
||||||
prey = self.planet[occupied_by_prey_coords[0]][occupied_by_prey_coords[1]]
|
|
||||||
assert prey is not None
|
|
||||||
prey.alive = False
|
|
||||||
|
|
||||||
# Move onto prey
|
|
||||||
self.planet[occupied_by_prey_coords[0]][occupied_by_prey_coords[1]] = entity
|
|
||||||
self.planet[entity.coords[0]][entity.coords[1]] = None
|
|
||||||
|
|
||||||
entity.coords = occupied_by_prey_coords
|
|
||||||
# (4.) Eats the prey and earns energy
|
|
||||||
entity.energy_value += PREDATOR_FOOD_VALUE
|
|
||||||
else:
|
|
||||||
# (5.) If it has survived the certain number of chronons it will also
|
|
||||||
# reproduce in this function
|
|
||||||
self.move_and_reproduce(entity, direction_orders)
|
|
||||||
|
|
||||||
# (2.) Each chronon, the predator is deprived of a unit of energy
|
|
||||||
entity.energy_value -= 1
|
|
||||||
|
|
||||||
def run(self, *, iteration_count: int) -> None:
|
|
||||||
"""
|
|
||||||
Emulate time passing by looping iteration_count times
|
|
||||||
|
|
||||||
>>> wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
>>> wt.run(iteration_count=PREDATOR_INITIAL_ENERGY_VALUE - 1)
|
|
||||||
>>> len(list(filter(lambda entity: entity.prey is False,
|
|
||||||
... wt.get_entities()))) >= PREDATOR_INITIAL_COUNT
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
for iter_num in range(iteration_count):
|
|
||||||
# Generate list of all entities in order to randomly
|
|
||||||
# pop an entity at a time to simulate true randomness
|
|
||||||
# This removes the systematic approach of iterating
|
|
||||||
# through each entity width by height
|
|
||||||
all_entities = self.get_entities()
|
|
||||||
|
|
||||||
for __ in range(len(all_entities)):
|
|
||||||
entity = all_entities.pop(randint(0, len(all_entities) - 1))
|
|
||||||
if entity.alive is False:
|
|
||||||
continue
|
|
||||||
|
|
||||||
directions: list[Literal["N", "E", "S", "W"]] = ["N", "E", "S", "W"]
|
|
||||||
shuffle(directions) # Randomly shuffle directions
|
|
||||||
|
|
||||||
if entity.prey:
|
|
||||||
self.perform_prey_actions(entity, directions)
|
|
||||||
else:
|
|
||||||
# Create list of surrounding prey
|
|
||||||
surrounding_prey = self.get_surrounding_prey(entity)
|
|
||||||
surrounding_prey_coords = None
|
|
||||||
|
|
||||||
if surrounding_prey:
|
|
||||||
# Again, randomly shuffle directions
|
|
||||||
shuffle(surrounding_prey)
|
|
||||||
surrounding_prey_coords = surrounding_prey[0].coords
|
|
||||||
|
|
||||||
self.perform_predator_actions(
|
|
||||||
entity, surrounding_prey_coords, directions
|
|
||||||
)
|
|
||||||
|
|
||||||
# Balance out the predators and prey
|
|
||||||
self.balance_predators_and_prey()
|
|
||||||
|
|
||||||
if self.time_passed is not None:
|
|
||||||
# Call time_passed function for Wa-Tor planet
|
|
||||||
# visualisation in a terminal or a graph.
|
|
||||||
self.time_passed(self, iter_num)
|
|
||||||
|
|
||||||
|
|
||||||
def visualise(wt: WaTor, iter_number: int, *, colour: bool = True) -> None:
|
|
||||||
"""
|
|
||||||
Visually displays the Wa-Tor planet using
|
|
||||||
an ascii code in terminal to clear and re-print
|
|
||||||
the Wa-Tor planet at intervals.
|
|
||||||
|
|
||||||
Uses ascii colour codes to colourfully display
|
|
||||||
the predators and prey.
|
|
||||||
|
|
||||||
(0x60f197) Prey = #
|
|
||||||
(0xfffff) Predator = x
|
|
||||||
|
|
||||||
>>> wt = WaTor(30, 30)
|
|
||||||
>>> wt.set_planet([
|
|
||||||
... [Entity(True, coords=(0, 0)), Entity(False, coords=(0, 1)), None],
|
|
||||||
... [Entity(False, coords=(1, 0)), None, Entity(False, coords=(1, 2))],
|
|
||||||
... [None, Entity(True, coords=(2, 1)), None]
|
|
||||||
... ])
|
|
||||||
>>> visualise(wt, 0, colour=False) # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
# x .
|
|
||||||
x . x
|
|
||||||
. # .
|
|
||||||
<BLANKLINE>
|
|
||||||
Iteration: 0 | Prey count: 2 | Predator count: 3 |
|
|
||||||
"""
|
|
||||||
if colour:
|
|
||||||
__import__("os").system("")
|
|
||||||
print("\x1b[0;0H\x1b[2J\x1b[?25l")
|
|
||||||
|
|
||||||
reprint = "\x1b[0;0H" if colour else ""
|
|
||||||
ansi_colour_end = "\x1b[0m " if colour else " "
|
|
||||||
|
|
||||||
planet = wt.planet
|
|
||||||
output = ""
|
|
||||||
|
|
||||||
# Iterate over every entity in the planet
|
|
||||||
for row in planet:
|
|
||||||
for entity in row:
|
|
||||||
if entity is None:
|
|
||||||
output += " . "
|
|
||||||
else:
|
|
||||||
if colour is True:
|
|
||||||
output += (
|
|
||||||
"\x1b[38;2;96;241;151m"
|
|
||||||
if entity.prey
|
|
||||||
else "\x1b[38;2;255;255;15m"
|
|
||||||
)
|
|
||||||
output += f" {'#' if entity.prey else 'x'}{ansi_colour_end}"
|
|
||||||
|
|
||||||
output += "\n"
|
|
||||||
|
|
||||||
entities = wt.get_entities()
|
|
||||||
prey_count = sum(entity.prey for entity in entities)
|
|
||||||
|
|
||||||
print(
|
|
||||||
f"{output}\n Iteration: {iter_number} | Prey count: {prey_count} | "
|
|
||||||
f"Predator count: {len(entities) - prey_count} | {reprint}"
|
|
||||||
)
|
|
||||||
# Block the thread to be able to visualise seeing the algorithm
|
|
||||||
sleep(0.05)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
doctest.testmod()
|
|
||||||
|
|
||||||
wt = WaTor(WIDTH, HEIGHT)
|
|
||||||
wt.time_passed = visualise
|
|
||||||
wt.run(iteration_count=100_000)
|
|
@ -10,13 +10,13 @@ primes = {
|
|||||||
5: {
|
5: {
|
||||||
"prime": int(
|
"prime": int(
|
||||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
||||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
||||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
||||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
||||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
||||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
||||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
||||||
"670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
|
+ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
|
||||||
base=16,
|
base=16,
|
||||||
),
|
),
|
||||||
"generator": 2,
|
"generator": 2,
|
||||||
@ -25,16 +25,16 @@ primes = {
|
|||||||
14: {
|
14: {
|
||||||
"prime": int(
|
"prime": int(
|
||||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
||||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
||||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
||||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
||||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
||||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
||||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
||||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
||||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
||||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
||||||
"15728E5A8AACAA68FFFFFFFFFFFFFFFF",
|
+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
|
||||||
base=16,
|
base=16,
|
||||||
),
|
),
|
||||||
"generator": 2,
|
"generator": 2,
|
||||||
@ -43,21 +43,21 @@ primes = {
|
|||||||
15: {
|
15: {
|
||||||
"prime": int(
|
"prime": int(
|
||||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
||||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
||||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
||||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
||||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
||||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
||||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
||||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
||||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
||||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
||||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
|
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
|
||||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
||||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
|
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
|
||||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
||||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
|
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
|
||||||
"43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
|
+ "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
|
||||||
base=16,
|
base=16,
|
||||||
),
|
),
|
||||||
"generator": 2,
|
"generator": 2,
|
||||||
@ -66,27 +66,27 @@ primes = {
|
|||||||
16: {
|
16: {
|
||||||
"prime": int(
|
"prime": int(
|
||||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
||||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
||||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
||||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
||||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
||||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
||||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
||||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
||||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
||||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
||||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
|
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
|
||||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
||||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
|
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
|
||||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
||||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
|
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
|
||||||
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
|
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
|
||||||
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
|
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
|
||||||
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
|
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
|
||||||
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
|
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
|
||||||
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
|
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
|
||||||
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
|
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
|
||||||
"FFFFFFFFFFFFFFFF",
|
+ "FFFFFFFFFFFFFFFF",
|
||||||
base=16,
|
base=16,
|
||||||
),
|
),
|
||||||
"generator": 2,
|
"generator": 2,
|
||||||
@ -95,33 +95,33 @@ primes = {
|
|||||||
17: {
|
17: {
|
||||||
"prime": int(
|
"prime": int(
|
||||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
|
||||||
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
|
+ "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
|
||||||
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
|
+ "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
|
||||||
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
|
+ "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
|
||||||
"49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
|
+ "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
|
||||||
"FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
+ "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
||||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
|
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
|
||||||
"180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
|
+ "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
|
||||||
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
|
+ "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
|
||||||
"04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
|
+ "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
|
||||||
"B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
|
+ "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
|
||||||
"1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
+ "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
||||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
|
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
|
||||||
"E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
|
+ "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
|
||||||
"99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
|
+ "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
|
||||||
"04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
|
+ "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
|
||||||
"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
|
+ "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
|
||||||
"D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
|
+ "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
|
||||||
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
|
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
|
||||||
"AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
|
+ "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
|
||||||
"DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
|
+ "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
|
||||||
"2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
|
+ "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
|
||||||
"F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
|
+ "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
|
||||||
"BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
|
+ "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
|
||||||
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
|
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
|
||||||
"B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
|
+ "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
|
||||||
"387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
|
+ "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
|
||||||
"6DCC4024FFFFFFFFFFFFFFFF",
|
+ "6DCC4024FFFFFFFFFFFFFFFF",
|
||||||
base=16,
|
base=16,
|
||||||
),
|
),
|
||||||
"generator": 2,
|
"generator": 2,
|
||||||
@ -130,48 +130,48 @@ primes = {
|
|||||||
18: {
|
18: {
|
||||||
"prime": int(
|
"prime": int(
|
||||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
||||||
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
||||||
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
||||||
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
||||||
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
|
||||||
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
|
||||||
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
|
||||||
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
||||||
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
|
||||||
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
|
||||||
"15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
|
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
|
||||||
"ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
||||||
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
|
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
|
||||||
"F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
|
||||||
"BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
|
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
|
||||||
"43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
|
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
|
||||||
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
|
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
|
||||||
"2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
|
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
|
||||||
"287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
|
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
|
||||||
"1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
|
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
|
||||||
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
|
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
|
||||||
"36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
|
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
|
||||||
"F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
|
+ "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
|
||||||
"179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
|
+ "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
|
||||||
"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
|
+ "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
|
||||||
"5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
|
+ "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
|
||||||
"D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
|
+ "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
|
||||||
"23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
|
+ "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
|
||||||
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
|
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
|
||||||
"06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
|
+ "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
|
||||||
"DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
|
+ "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
|
||||||
"12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
|
+ "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
|
||||||
"38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
|
+ "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
|
||||||
"741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
|
+ "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
|
||||||
"3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
|
+ "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
|
||||||
"22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
|
+ "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
|
||||||
"4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
|
+ "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
|
||||||
"062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
|
+ "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
|
||||||
"4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
|
+ "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
|
||||||
"B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
|
+ "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
|
||||||
"4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
|
+ "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
|
||||||
"9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
|
+ "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
|
||||||
"60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
|
+ "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
|
||||||
base=16,
|
base=16,
|
||||||
),
|
),
|
||||||
"generator": 2,
|
"generator": 2,
|
||||||
|
@ -150,7 +150,7 @@ def reverse_bwt(bwt_string: str, idx_original_string: int) -> str:
|
|||||||
raise ValueError("The parameter idx_original_string must not be lower than 0.")
|
raise ValueError("The parameter idx_original_string must not be lower than 0.")
|
||||||
if idx_original_string >= len(bwt_string):
|
if idx_original_string >= len(bwt_string):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The parameter idx_original_string must be lower than len(bwt_string)."
|
"The parameter idx_original_string must be lower than" " len(bwt_string)."
|
||||||
)
|
)
|
||||||
|
|
||||||
ordered_rotations = [""] * len(bwt_string)
|
ordered_rotations = [""] * len(bwt_string)
|
||||||
|
@ -22,13 +22,9 @@ REFERENCES :
|
|||||||
-> Wikipedia reference: https://en.wikipedia.org/wiki/Millimeter
|
-> Wikipedia reference: https://en.wikipedia.org/wiki/Millimeter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import NamedTuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
class FromTo(NamedTuple):
|
|
||||||
from_factor: float
|
|
||||||
to_factor: float
|
|
||||||
|
|
||||||
|
from_to = namedtuple("from_to", "from_ to")
|
||||||
|
|
||||||
TYPE_CONVERSION = {
|
TYPE_CONVERSION = {
|
||||||
"millimeter": "mm",
|
"millimeter": "mm",
|
||||||
@ -44,14 +40,14 @@ TYPE_CONVERSION = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
METRIC_CONVERSION = {
|
METRIC_CONVERSION = {
|
||||||
"mm": FromTo(0.001, 1000),
|
"mm": from_to(0.001, 1000),
|
||||||
"cm": FromTo(0.01, 100),
|
"cm": from_to(0.01, 100),
|
||||||
"m": FromTo(1, 1),
|
"m": from_to(1, 1),
|
||||||
"km": FromTo(1000, 0.001),
|
"km": from_to(1000, 0.001),
|
||||||
"in": FromTo(0.0254, 39.3701),
|
"in": from_to(0.0254, 39.3701),
|
||||||
"ft": FromTo(0.3048, 3.28084),
|
"ft": from_to(0.3048, 3.28084),
|
||||||
"yd": FromTo(0.9144, 1.09361),
|
"yd": from_to(0.9144, 1.09361),
|
||||||
"mi": FromTo(1609.34, 0.000621371),
|
"mi": from_to(1609.34, 0.000621371),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -119,11 +115,7 @@ def length_conversion(value: float, from_type: str, to_type: str) -> float:
|
|||||||
f"Conversion abbreviations are: {', '.join(METRIC_CONVERSION)}"
|
f"Conversion abbreviations are: {', '.join(METRIC_CONVERSION)}"
|
||||||
)
|
)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
return (
|
return value * METRIC_CONVERSION[new_from].from_ * METRIC_CONVERSION[new_to].to
|
||||||
value
|
|
||||||
* METRIC_CONVERSION[new_from].from_factor
|
|
||||||
* METRIC_CONVERSION[new_to].to_factor
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -19,23 +19,19 @@ REFERENCES :
|
|||||||
-> https://www.unitconverters.net/pressure-converter.html
|
-> https://www.unitconverters.net/pressure-converter.html
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import NamedTuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
class FromTo(NamedTuple):
|
|
||||||
from_factor: float
|
|
||||||
to_factor: float
|
|
||||||
|
|
||||||
|
from_to = namedtuple("from_to", "from_ to")
|
||||||
|
|
||||||
PRESSURE_CONVERSION = {
|
PRESSURE_CONVERSION = {
|
||||||
"atm": FromTo(1, 1),
|
"atm": from_to(1, 1),
|
||||||
"pascal": FromTo(0.0000098, 101325),
|
"pascal": from_to(0.0000098, 101325),
|
||||||
"bar": FromTo(0.986923, 1.01325),
|
"bar": from_to(0.986923, 1.01325),
|
||||||
"kilopascal": FromTo(0.00986923, 101.325),
|
"kilopascal": from_to(0.00986923, 101.325),
|
||||||
"megapascal": FromTo(9.86923, 0.101325),
|
"megapascal": from_to(9.86923, 0.101325),
|
||||||
"psi": FromTo(0.068046, 14.6959),
|
"psi": from_to(0.068046, 14.6959),
|
||||||
"inHg": FromTo(0.0334211, 29.9213),
|
"inHg": from_to(0.0334211, 29.9213),
|
||||||
"torr": FromTo(0.00131579, 760),
|
"torr": from_to(0.00131579, 760),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -75,9 +71,7 @@ def pressure_conversion(value: float, from_type: str, to_type: str) -> float:
|
|||||||
+ ", ".join(PRESSURE_CONVERSION)
|
+ ", ".join(PRESSURE_CONVERSION)
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
value
|
value * PRESSURE_CONVERSION[from_type].from_ * PRESSURE_CONVERSION[to_type].to
|
||||||
* PRESSURE_CONVERSION[from_type].from_factor
|
|
||||||
* PRESSURE_CONVERSION[to_type].to_factor
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,39 +18,35 @@ REFERENCES :
|
|||||||
-> Wikipedia reference: https://en.wikipedia.org/wiki/Cup_(unit)
|
-> Wikipedia reference: https://en.wikipedia.org/wiki/Cup_(unit)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import NamedTuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
class FromTo(NamedTuple):
|
|
||||||
from_factor: float
|
|
||||||
to_factor: float
|
|
||||||
|
|
||||||
|
from_to = namedtuple("from_to", "from_ to")
|
||||||
|
|
||||||
METRIC_CONVERSION = {
|
METRIC_CONVERSION = {
|
||||||
"cubic meter": FromTo(1, 1),
|
"cubicmeter": from_to(1, 1),
|
||||||
"litre": FromTo(0.001, 1000),
|
"litre": from_to(0.001, 1000),
|
||||||
"kilolitre": FromTo(1, 1),
|
"kilolitre": from_to(1, 1),
|
||||||
"gallon": FromTo(0.00454, 264.172),
|
"gallon": from_to(0.00454, 264.172),
|
||||||
"cubic yard": FromTo(0.76455, 1.30795),
|
"cubicyard": from_to(0.76455, 1.30795),
|
||||||
"cubic foot": FromTo(0.028, 35.3147),
|
"cubicfoot": from_to(0.028, 35.3147),
|
||||||
"cup": FromTo(0.000236588, 4226.75),
|
"cup": from_to(0.000236588, 4226.75),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def volume_conversion(value: float, from_type: str, to_type: str) -> float:
|
def volume_conversion(value: float, from_type: str, to_type: str) -> float:
|
||||||
"""
|
"""
|
||||||
Conversion between volume units.
|
Conversion between volume units.
|
||||||
>>> volume_conversion(4, "cubic meter", "litre")
|
>>> volume_conversion(4, "cubicmeter", "litre")
|
||||||
4000
|
4000
|
||||||
>>> volume_conversion(1, "litre", "gallon")
|
>>> volume_conversion(1, "litre", "gallon")
|
||||||
0.264172
|
0.264172
|
||||||
>>> volume_conversion(1, "kilolitre", "cubic meter")
|
>>> volume_conversion(1, "kilolitre", "cubicmeter")
|
||||||
1
|
1
|
||||||
>>> volume_conversion(3, "gallon", "cubic yard")
|
>>> volume_conversion(3, "gallon", "cubicyard")
|
||||||
0.017814279
|
0.017814279
|
||||||
>>> volume_conversion(2, "cubic yard", "litre")
|
>>> volume_conversion(2, "cubicyard", "litre")
|
||||||
1529.1
|
1529.1
|
||||||
>>> volume_conversion(4, "cubic foot", "cup")
|
>>> volume_conversion(4, "cubicfoot", "cup")
|
||||||
473.396
|
473.396
|
||||||
>>> volume_conversion(1, "cup", "kilolitre")
|
>>> volume_conversion(1, "cup", "kilolitre")
|
||||||
0.000236588
|
0.000236588
|
||||||
@ -58,7 +54,7 @@ def volume_conversion(value: float, from_type: str, to_type: str) -> float:
|
|||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValueError: Invalid 'from_type' value: 'wrongUnit' Supported values are:
|
ValueError: Invalid 'from_type' value: 'wrongUnit' Supported values are:
|
||||||
cubic meter, litre, kilolitre, gallon, cubic yard, cubic foot, cup
|
cubicmeter, litre, kilolitre, gallon, cubicyard, cubicfoot, cup
|
||||||
"""
|
"""
|
||||||
if from_type not in METRIC_CONVERSION:
|
if from_type not in METRIC_CONVERSION:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@ -70,11 +66,7 @@ def volume_conversion(value: float, from_type: str, to_type: str) -> float:
|
|||||||
f"Invalid 'to_type' value: {to_type!r}. Supported values are:\n"
|
f"Invalid 'to_type' value: {to_type!r}. Supported values are:\n"
|
||||||
+ ", ".join(METRIC_CONVERSION)
|
+ ", ".join(METRIC_CONVERSION)
|
||||||
)
|
)
|
||||||
return (
|
return value * METRIC_CONVERSION[from_type].from_ * METRIC_CONVERSION[to_type].to
|
||||||
value
|
|
||||||
* METRIC_CONVERSION[from_type].from_factor
|
|
||||||
* METRIC_CONVERSION[to_type].to_factor
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -58,19 +58,6 @@ def inorder(root: Node | None) -> list[int]:
|
|||||||
return [*inorder(root.left), root.data, *inorder(root.right)] if root else []
|
return [*inorder(root.left), root.data, *inorder(root.right)] if root else []
|
||||||
|
|
||||||
|
|
||||||
def reverse_inorder(root: Node | None) -> list[int]:
|
|
||||||
"""
|
|
||||||
Reverse in-order traversal visits right subtree, root node, left subtree.
|
|
||||||
>>> reverse_inorder(make_tree())
|
|
||||||
[3, 1, 5, 2, 4]
|
|
||||||
"""
|
|
||||||
return (
|
|
||||||
[*reverse_inorder(root.right), root.data, *reverse_inorder(root.left)]
|
|
||||||
if root
|
|
||||||
else []
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def height(root: Node | None) -> int:
|
def height(root: Node | None) -> int:
|
||||||
"""
|
"""
|
||||||
Recursive function for calculating the height of the binary tree.
|
Recursive function for calculating the height of the binary tree.
|
||||||
@ -174,12 +161,15 @@ def zigzag(root: Node | None) -> Sequence[Node | None] | list[Any]:
|
|||||||
|
|
||||||
|
|
||||||
def main() -> None: # Main function for testing.
|
def main() -> None: # Main function for testing.
|
||||||
# Create binary tree.
|
"""
|
||||||
|
Create binary tree.
|
||||||
|
"""
|
||||||
root = make_tree()
|
root = make_tree()
|
||||||
|
"""
|
||||||
|
All Traversals of the binary are as follows:
|
||||||
|
"""
|
||||||
|
|
||||||
# All Traversals of the binary are as follows:
|
|
||||||
print(f"In-order Traversal: {inorder(root)}")
|
print(f"In-order Traversal: {inorder(root)}")
|
||||||
print(f"Reverse In-order Traversal: {reverse_inorder(root)}")
|
|
||||||
print(f"Pre-order Traversal: {preorder(root)}")
|
print(f"Pre-order Traversal: {preorder(root)}")
|
||||||
print(f"Post-order Traversal: {postorder(root)}", "\n")
|
print(f"Post-order Traversal: {postorder(root)}", "\n")
|
||||||
|
|
||||||
|
@ -39,8 +39,8 @@ Space: O(1)
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import NamedTuple
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -50,9 +50,7 @@ class TreeNode:
|
|||||||
right: TreeNode | None = None
|
right: TreeNode | None = None
|
||||||
|
|
||||||
|
|
||||||
class CoinsDistribResult(NamedTuple):
|
CoinsDistribResult = namedtuple("CoinsDistribResult", "moves excess")
|
||||||
moves: int
|
|
||||||
excess: int
|
|
||||||
|
|
||||||
|
|
||||||
def distribute_coins(root: TreeNode | None) -> int:
|
def distribute_coins(root: TreeNode | None) -> int:
|
||||||
@ -81,7 +79,7 @@ def distribute_coins(root: TreeNode | None) -> int:
|
|||||||
# Validation
|
# Validation
|
||||||
def count_nodes(node: TreeNode | None) -> int:
|
def count_nodes(node: TreeNode | None) -> int:
|
||||||
"""
|
"""
|
||||||
>>> count_nodes(None)
|
>>> count_nodes(None):
|
||||||
0
|
0
|
||||||
"""
|
"""
|
||||||
if node is None:
|
if node is None:
|
||||||
@ -91,7 +89,7 @@ def distribute_coins(root: TreeNode | None) -> int:
|
|||||||
|
|
||||||
def count_coins(node: TreeNode | None) -> int:
|
def count_coins(node: TreeNode | None) -> int:
|
||||||
"""
|
"""
|
||||||
>>> count_coins(None)
|
>>> count_coins(None):
|
||||||
0
|
0
|
||||||
"""
|
"""
|
||||||
if node is None:
|
if node is None:
|
||||||
|
@ -7,8 +7,7 @@ class SegmentTree:
|
|||||||
self.st = [0] * (
|
self.st = [0] * (
|
||||||
4 * self.N
|
4 * self.N
|
||||||
) # approximate the overall size of segment tree with array N
|
) # approximate the overall size of segment tree with array N
|
||||||
if self.N:
|
self.build(1, 0, self.N - 1)
|
||||||
self.build(1, 0, self.N - 1)
|
|
||||||
|
|
||||||
def left(self, idx):
|
def left(self, idx):
|
||||||
return idx * 2
|
return idx * 2
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
"""Queue represented by a Python list"""
|
|
||||||
|
|
||||||
from collections.abc import Iterable
|
|
||||||
from typing import Generic, TypeVar
|
|
||||||
|
|
||||||
_T = TypeVar("_T")
|
|
||||||
|
|
||||||
|
|
||||||
class QueueByList(Generic[_T]):
|
|
||||||
def __init__(self, iterable: Iterable[_T] | None = None) -> None:
|
|
||||||
"""
|
|
||||||
>>> QueueByList()
|
|
||||||
Queue(())
|
|
||||||
>>> QueueByList([10, 20, 30])
|
|
||||||
Queue((10, 20, 30))
|
|
||||||
>>> QueueByList((i**2 for i in range(1, 4)))
|
|
||||||
Queue((1, 4, 9))
|
|
||||||
"""
|
|
||||||
self.entries: list[_T] = list(iterable or [])
|
|
||||||
|
|
||||||
def __len__(self) -> int:
|
|
||||||
"""
|
|
||||||
>>> len(QueueByList())
|
|
||||||
0
|
|
||||||
>>> from string import ascii_lowercase
|
|
||||||
>>> len(QueueByList(ascii_lowercase))
|
|
||||||
26
|
|
||||||
>>> queue = QueueByList()
|
|
||||||
>>> for i in range(1, 11):
|
|
||||||
... queue.put(i)
|
|
||||||
>>> len(queue)
|
|
||||||
10
|
|
||||||
>>> for i in range(2):
|
|
||||||
... queue.get()
|
|
||||||
1
|
|
||||||
2
|
|
||||||
>>> len(queue)
|
|
||||||
8
|
|
||||||
"""
|
|
||||||
|
|
||||||
return len(self.entries)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
"""
|
|
||||||
>>> queue = QueueByList()
|
|
||||||
>>> queue
|
|
||||||
Queue(())
|
|
||||||
>>> str(queue)
|
|
||||||
'Queue(())'
|
|
||||||
>>> queue.put(10)
|
|
||||||
>>> queue
|
|
||||||
Queue((10,))
|
|
||||||
>>> queue.put(20)
|
|
||||||
>>> queue.put(30)
|
|
||||||
>>> queue
|
|
||||||
Queue((10, 20, 30))
|
|
||||||
"""
|
|
||||||
|
|
||||||
return f"Queue({tuple(self.entries)})"
|
|
||||||
|
|
||||||
def put(self, item: _T) -> None:
|
|
||||||
"""Put `item` to the Queue
|
|
||||||
|
|
||||||
>>> queue = QueueByList()
|
|
||||||
>>> queue.put(10)
|
|
||||||
>>> queue.put(20)
|
|
||||||
>>> len(queue)
|
|
||||||
2
|
|
||||||
>>> queue
|
|
||||||
Queue((10, 20))
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.entries.append(item)
|
|
||||||
|
|
||||||
def get(self) -> _T:
|
|
||||||
"""
|
|
||||||
Get `item` from the Queue
|
|
||||||
|
|
||||||
>>> queue = QueueByList((10, 20, 30))
|
|
||||||
>>> queue.get()
|
|
||||||
10
|
|
||||||
>>> queue.put(40)
|
|
||||||
>>> queue.get()
|
|
||||||
20
|
|
||||||
>>> queue.get()
|
|
||||||
30
|
|
||||||
>>> len(queue)
|
|
||||||
1
|
|
||||||
>>> queue.get()
|
|
||||||
40
|
|
||||||
>>> queue.get()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
IndexError: Queue is empty
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not self.entries:
|
|
||||||
raise IndexError("Queue is empty")
|
|
||||||
return self.entries.pop(0)
|
|
||||||
|
|
||||||
def rotate(self, rotation: int) -> None:
|
|
||||||
"""Rotate the items of the Queue `rotation` times
|
|
||||||
|
|
||||||
>>> queue = QueueByList([10, 20, 30, 40])
|
|
||||||
>>> queue
|
|
||||||
Queue((10, 20, 30, 40))
|
|
||||||
>>> queue.rotate(1)
|
|
||||||
>>> queue
|
|
||||||
Queue((20, 30, 40, 10))
|
|
||||||
>>> queue.rotate(2)
|
|
||||||
>>> queue
|
|
||||||
Queue((40, 10, 20, 30))
|
|
||||||
"""
|
|
||||||
|
|
||||||
put = self.entries.append
|
|
||||||
get = self.entries.pop
|
|
||||||
|
|
||||||
for _ in range(rotation):
|
|
||||||
put(get(0))
|
|
||||||
|
|
||||||
def get_front(self) -> _T:
|
|
||||||
"""Get the front item from the Queue
|
|
||||||
|
|
||||||
>>> queue = QueueByList((10, 20, 30))
|
|
||||||
>>> queue.get_front()
|
|
||||||
10
|
|
||||||
>>> queue
|
|
||||||
Queue((10, 20, 30))
|
|
||||||
>>> queue.get()
|
|
||||||
10
|
|
||||||
>>> queue.get_front()
|
|
||||||
20
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.entries[0]
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
from doctest import testmod
|
|
||||||
|
|
||||||
testmod()
|
|
52
data_structures/queue/queue_on_list.py
Normal file
52
data_structures/queue/queue_on_list.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
"""Queue represented by a Python list"""
|
||||||
|
|
||||||
|
|
||||||
|
class Queue:
|
||||||
|
def __init__(self):
|
||||||
|
self.entries = []
|
||||||
|
self.length = 0
|
||||||
|
self.front = 0
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
printed = "<" + str(self.entries)[1:-1] + ">"
|
||||||
|
return printed
|
||||||
|
|
||||||
|
"""Enqueues {@code item}
|
||||||
|
@param item
|
||||||
|
item to enqueue"""
|
||||||
|
|
||||||
|
def put(self, item):
|
||||||
|
self.entries.append(item)
|
||||||
|
self.length = self.length + 1
|
||||||
|
|
||||||
|
"""Dequeues {@code item}
|
||||||
|
@requirement: |self.length| > 0
|
||||||
|
@return dequeued
|
||||||
|
item that was dequeued"""
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
self.length = self.length - 1
|
||||||
|
dequeued = self.entries[self.front]
|
||||||
|
# self.front-=1
|
||||||
|
# self.entries = self.entries[self.front:]
|
||||||
|
self.entries = self.entries[1:]
|
||||||
|
return dequeued
|
||||||
|
|
||||||
|
"""Rotates the queue {@code rotation} times
|
||||||
|
@param rotation
|
||||||
|
number of times to rotate queue"""
|
||||||
|
|
||||||
|
def rotate(self, rotation):
|
||||||
|
for _ in range(rotation):
|
||||||
|
self.put(self.get())
|
||||||
|
|
||||||
|
"""Enqueues {@code item}
|
||||||
|
@return item at front of self.entries"""
|
||||||
|
|
||||||
|
def get_front(self):
|
||||||
|
return self.entries[0]
|
||||||
|
|
||||||
|
"""Returns the length of this.entries"""
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
return self.length
|
@ -4,26 +4,9 @@ https://en.wikipedia.org/wiki/Reverse_Polish_notation
|
|||||||
https://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
https://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Literal
|
|
||||||
|
|
||||||
from .balanced_parentheses import balanced_parentheses
|
from .balanced_parentheses import balanced_parentheses
|
||||||
from .stack import Stack
|
from .stack import Stack
|
||||||
|
|
||||||
PRECEDENCES: dict[str, int] = {
|
|
||||||
"+": 1,
|
|
||||||
"-": 1,
|
|
||||||
"*": 2,
|
|
||||||
"/": 2,
|
|
||||||
"^": 3,
|
|
||||||
}
|
|
||||||
ASSOCIATIVITIES: dict[str, Literal["LR", "RL"]] = {
|
|
||||||
"+": "LR",
|
|
||||||
"-": "LR",
|
|
||||||
"*": "LR",
|
|
||||||
"/": "LR",
|
|
||||||
"^": "RL",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def precedence(char: str) -> int:
|
def precedence(char: str) -> int:
|
||||||
"""
|
"""
|
||||||
@ -31,15 +14,7 @@ def precedence(char: str) -> int:
|
|||||||
order of operation.
|
order of operation.
|
||||||
https://en.wikipedia.org/wiki/Order_of_operations
|
https://en.wikipedia.org/wiki/Order_of_operations
|
||||||
"""
|
"""
|
||||||
return PRECEDENCES.get(char, -1)
|
return {"+": 1, "-": 1, "*": 2, "/": 2, "^": 3}.get(char, -1)
|
||||||
|
|
||||||
|
|
||||||
def associativity(char: str) -> Literal["LR", "RL"]:
|
|
||||||
"""
|
|
||||||
Return the associativity of the operator `char`.
|
|
||||||
https://en.wikipedia.org/wiki/Operator_associativity
|
|
||||||
"""
|
|
||||||
return ASSOCIATIVITIES[char]
|
|
||||||
|
|
||||||
|
|
||||||
def infix_to_postfix(expression_str: str) -> str:
|
def infix_to_postfix(expression_str: str) -> str:
|
||||||
@ -60,8 +35,6 @@ def infix_to_postfix(expression_str: str) -> str:
|
|||||||
'a b c * + d e * f + g * +'
|
'a b c * + d e * f + g * +'
|
||||||
>>> infix_to_postfix("x^y/(5*z)+2")
|
>>> infix_to_postfix("x^y/(5*z)+2")
|
||||||
'x y ^ 5 z * / 2 +'
|
'x y ^ 5 z * / 2 +'
|
||||||
>>> infix_to_postfix("2^3^2")
|
|
||||||
'2 3 2 ^ ^'
|
|
||||||
"""
|
"""
|
||||||
if not balanced_parentheses(expression_str):
|
if not balanced_parentheses(expression_str):
|
||||||
raise ValueError("Mismatched parentheses")
|
raise ValueError("Mismatched parentheses")
|
||||||
@ -77,26 +50,9 @@ def infix_to_postfix(expression_str: str) -> str:
|
|||||||
postfix.append(stack.pop())
|
postfix.append(stack.pop())
|
||||||
stack.pop()
|
stack.pop()
|
||||||
else:
|
else:
|
||||||
while True:
|
while not stack.is_empty() and precedence(char) <= precedence(stack.peek()):
|
||||||
if stack.is_empty():
|
|
||||||
stack.push(char)
|
|
||||||
break
|
|
||||||
|
|
||||||
char_precedence = precedence(char)
|
|
||||||
tos_precedence = precedence(stack.peek())
|
|
||||||
|
|
||||||
if char_precedence > tos_precedence:
|
|
||||||
stack.push(char)
|
|
||||||
break
|
|
||||||
if char_precedence < tos_precedence:
|
|
||||||
postfix.append(stack.pop())
|
|
||||||
continue
|
|
||||||
# Precedences are equal
|
|
||||||
if associativity(char) == "RL":
|
|
||||||
stack.push(char)
|
|
||||||
break
|
|
||||||
postfix.append(stack.pop())
|
postfix.append(stack.pop())
|
||||||
|
stack.push(char)
|
||||||
while not stack.is_empty():
|
while not stack.is_empty():
|
||||||
postfix.append(stack.pop())
|
postfix.append(stack.pop())
|
||||||
return " ".join(postfix)
|
return " ".join(postfix)
|
||||||
|
@ -39,18 +39,9 @@ class Burkes:
|
|||||||
def get_greyscale(cls, blue: int, green: int, red: int) -> float:
|
def get_greyscale(cls, blue: int, green: int, red: int) -> float:
|
||||||
"""
|
"""
|
||||||
>>> Burkes.get_greyscale(3, 4, 5)
|
>>> Burkes.get_greyscale(3, 4, 5)
|
||||||
4.185
|
3.753
|
||||||
>>> Burkes.get_greyscale(0, 0, 0)
|
|
||||||
0.0
|
|
||||||
>>> Burkes.get_greyscale(255, 255, 255)
|
|
||||||
255.0
|
|
||||||
"""
|
"""
|
||||||
"""
|
return 0.114 * blue + 0.587 * green + 0.2126 * red
|
||||||
Formula from https://en.wikipedia.org/wiki/HSL_and_HSV
|
|
||||||
cf Lightness section, and Fig 13c.
|
|
||||||
We use the first of four possible.
|
|
||||||
"""
|
|
||||||
return 0.114 * blue + 0.587 * green + 0.299 * red
|
|
||||||
|
|
||||||
def process(self) -> None:
|
def process(self) -> None:
|
||||||
for y in range(self.height):
|
for y in range(self.height):
|
||||||
@ -58,10 +49,10 @@ class Burkes:
|
|||||||
greyscale = int(self.get_greyscale(*self.input_img[y][x]))
|
greyscale = int(self.get_greyscale(*self.input_img[y][x]))
|
||||||
if self.threshold > greyscale + self.error_table[y][x]:
|
if self.threshold > greyscale + self.error_table[y][x]:
|
||||||
self.output_img[y][x] = (0, 0, 0)
|
self.output_img[y][x] = (0, 0, 0)
|
||||||
current_error = greyscale + self.error_table[y][x]
|
current_error = greyscale + self.error_table[x][y]
|
||||||
else:
|
else:
|
||||||
self.output_img[y][x] = (255, 255, 255)
|
self.output_img[y][x] = (255, 255, 255)
|
||||||
current_error = greyscale + self.error_table[y][x] - 255
|
current_error = greyscale + self.error_table[x][y] - 255
|
||||||
"""
|
"""
|
||||||
Burkes error propagation (`*` is current pixel):
|
Burkes error propagation (`*` is current pixel):
|
||||||
|
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
"""
|
|
||||||
Regex matching check if a text matches pattern or not.
|
|
||||||
Pattern:
|
|
||||||
'.' Matches any single character.
|
|
||||||
'*' Matches zero or more of the preceding element.
|
|
||||||
More info:
|
|
||||||
https://medium.com/trick-the-interviwer/regular-expression-matching-9972eb74c03
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def recursive_match(text: str, pattern: str) -> bool:
|
|
||||||
"""
|
|
||||||
Recursive matching algorithm.
|
|
||||||
|
|
||||||
Time complexity: O(2 ^ (|text| + |pattern|))
|
|
||||||
Space complexity: Recursion depth is O(|text| + |pattern|).
|
|
||||||
|
|
||||||
:param text: Text to match.
|
|
||||||
:param pattern: Pattern to match.
|
|
||||||
:return: True if text matches pattern, False otherwise.
|
|
||||||
|
|
||||||
>>> recursive_match('abc', 'a.c')
|
|
||||||
True
|
|
||||||
>>> recursive_match('abc', 'af*.c')
|
|
||||||
True
|
|
||||||
>>> recursive_match('abc', 'a.c*')
|
|
||||||
True
|
|
||||||
>>> recursive_match('abc', 'a.c*d')
|
|
||||||
False
|
|
||||||
>>> recursive_match('aa', '.*')
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
if not pattern:
|
|
||||||
return not text
|
|
||||||
|
|
||||||
if not text:
|
|
||||||
return pattern[-1] == "*" and recursive_match(text, pattern[:-2])
|
|
||||||
|
|
||||||
if text[-1] == pattern[-1] or pattern[-1] == ".":
|
|
||||||
return recursive_match(text[:-1], pattern[:-1])
|
|
||||||
|
|
||||||
if pattern[-1] == "*":
|
|
||||||
return recursive_match(text[:-1], pattern) or recursive_match(
|
|
||||||
text, pattern[:-2]
|
|
||||||
)
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def dp_match(text: str, pattern: str) -> bool:
|
|
||||||
"""
|
|
||||||
Dynamic programming matching algorithm.
|
|
||||||
|
|
||||||
Time complexity: O(|text| * |pattern|)
|
|
||||||
Space complexity: O(|text| * |pattern|)
|
|
||||||
|
|
||||||
:param text: Text to match.
|
|
||||||
:param pattern: Pattern to match.
|
|
||||||
:return: True if text matches pattern, False otherwise.
|
|
||||||
|
|
||||||
>>> dp_match('abc', 'a.c')
|
|
||||||
True
|
|
||||||
>>> dp_match('abc', 'af*.c')
|
|
||||||
True
|
|
||||||
>>> dp_match('abc', 'a.c*')
|
|
||||||
True
|
|
||||||
>>> dp_match('abc', 'a.c*d')
|
|
||||||
False
|
|
||||||
>>> dp_match('aa', '.*')
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
m = len(text)
|
|
||||||
n = len(pattern)
|
|
||||||
dp = [[False for _ in range(n + 1)] for _ in range(m + 1)]
|
|
||||||
dp[0][0] = True
|
|
||||||
|
|
||||||
for j in range(1, n + 1):
|
|
||||||
dp[0][j] = pattern[j - 1] == "*" and dp[0][j - 2]
|
|
||||||
|
|
||||||
for i in range(1, m + 1):
|
|
||||||
for j in range(1, n + 1):
|
|
||||||
if pattern[j - 1] in {".", text[i - 1]}:
|
|
||||||
dp[i][j] = dp[i - 1][j - 1]
|
|
||||||
elif pattern[j - 1] == "*":
|
|
||||||
dp[i][j] = dp[i][j - 2]
|
|
||||||
if pattern[j - 2] in {".", text[i - 1]}:
|
|
||||||
dp[i][j] |= dp[i - 1][j]
|
|
||||||
else:
|
|
||||||
dp[i][j] = False
|
|
||||||
|
|
||||||
return dp[m][n]
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
doctest.testmod()
|
|
@ -1,24 +0,0 @@
|
|||||||
# Tribonacci sequence using Dynamic Programming
|
|
||||||
|
|
||||||
|
|
||||||
def tribonacci(num: int) -> list[int]:
|
|
||||||
"""
|
|
||||||
Given a number, return first n Tribonacci Numbers.
|
|
||||||
>>> tribonacci(5)
|
|
||||||
[0, 0, 1, 1, 2]
|
|
||||||
>>> tribonacci(8)
|
|
||||||
[0, 0, 1, 1, 2, 4, 7, 13]
|
|
||||||
"""
|
|
||||||
dp = [0] * num
|
|
||||||
dp[2] = 1
|
|
||||||
|
|
||||||
for i in range(3, num):
|
|
||||||
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]
|
|
||||||
|
|
||||||
return dp
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
doctest.testmod()
|
|
@ -1,12 +1,7 @@
|
|||||||
# https://en.m.wikipedia.org/wiki/Electric_power
|
# https://en.m.wikipedia.org/wiki/Electric_power
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import NamedTuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
class Result(NamedTuple):
|
|
||||||
name: str
|
|
||||||
value: float
|
|
||||||
|
|
||||||
|
|
||||||
def electric_power(voltage: float, current: float, power: float) -> tuple:
|
def electric_power(voltage: float, current: float, power: float) -> tuple:
|
||||||
@ -15,11 +10,11 @@ def electric_power(voltage: float, current: float, power: float) -> tuple:
|
|||||||
fundamental value of electrical system.
|
fundamental value of electrical system.
|
||||||
examples are below:
|
examples are below:
|
||||||
>>> electric_power(voltage=0, current=2, power=5)
|
>>> electric_power(voltage=0, current=2, power=5)
|
||||||
Result(name='voltage', value=2.5)
|
result(name='voltage', value=2.5)
|
||||||
>>> electric_power(voltage=2, current=2, power=0)
|
>>> electric_power(voltage=2, current=2, power=0)
|
||||||
Result(name='power', value=4.0)
|
result(name='power', value=4.0)
|
||||||
>>> electric_power(voltage=-2, current=3, power=0)
|
>>> electric_power(voltage=-2, current=3, power=0)
|
||||||
Result(name='power', value=6.0)
|
result(name='power', value=6.0)
|
||||||
>>> electric_power(voltage=2, current=4, power=2)
|
>>> electric_power(voltage=2, current=4, power=2)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
@ -33,8 +28,9 @@ def electric_power(voltage: float, current: float, power: float) -> tuple:
|
|||||||
...
|
...
|
||||||
ValueError: Power cannot be negative in any electrical/electronics system
|
ValueError: Power cannot be negative in any electrical/electronics system
|
||||||
>>> electric_power(voltage=2.2, current=2.2, power=0)
|
>>> electric_power(voltage=2.2, current=2.2, power=0)
|
||||||
Result(name='power', value=4.84)
|
result(name='power', value=4.84)
|
||||||
"""
|
"""
|
||||||
|
result = namedtuple("result", "name value")
|
||||||
if (voltage, current, power).count(0) != 1:
|
if (voltage, current, power).count(0) != 1:
|
||||||
raise ValueError("Only one argument must be 0")
|
raise ValueError("Only one argument must be 0")
|
||||||
elif power < 0:
|
elif power < 0:
|
||||||
@ -42,11 +38,11 @@ def electric_power(voltage: float, current: float, power: float) -> tuple:
|
|||||||
"Power cannot be negative in any electrical/electronics system"
|
"Power cannot be negative in any electrical/electronics system"
|
||||||
)
|
)
|
||||||
elif voltage == 0:
|
elif voltage == 0:
|
||||||
return Result("voltage", power / current)
|
return result("voltage", power / current)
|
||||||
elif current == 0:
|
elif current == 0:
|
||||||
return Result("current", power / voltage)
|
return result("current", power / voltage)
|
||||||
elif power == 0:
|
elif power == 0:
|
||||||
return Result("power", float(round(abs(voltage * current), 2)))
|
return result("power", float(round(abs(voltage * current), 2)))
|
||||||
else:
|
else:
|
||||||
raise ValueError("Exactly one argument must be 0")
|
raise ValueError("Exactly one argument must be 0")
|
||||||
|
|
||||||
|
@ -82,4 +82,3 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
vertices = [(-175, -125), (0, 175), (175, -125)] # vertices of triangle
|
vertices = [(-175, -125), (0, 175), (175, -125)] # vertices of triangle
|
||||||
triangle(vertices[0], vertices[1], vertices[2], int(sys.argv[1]))
|
triangle(vertices[0], vertices[1], vertices[2], int(sys.argv[1]))
|
||||||
turtle.Screen().exitonclick()
|
|
||||||
|
@ -26,8 +26,8 @@ def pass_and_relaxation(
|
|||||||
cst_bwd: dict,
|
cst_bwd: dict,
|
||||||
queue: PriorityQueue,
|
queue: PriorityQueue,
|
||||||
parent: dict,
|
parent: dict,
|
||||||
shortest_distance: float,
|
shortest_distance: float | int,
|
||||||
) -> float:
|
) -> float | int:
|
||||||
for nxt, d in graph[v]:
|
for nxt, d in graph[v]:
|
||||||
if nxt in visited_forward:
|
if nxt in visited_forward:
|
||||||
continue
|
continue
|
||||||
|
@ -20,7 +20,7 @@ def check_circuit_or_path(graph, max_node):
|
|||||||
odd_degree_nodes = 0
|
odd_degree_nodes = 0
|
||||||
odd_node = -1
|
odd_node = -1
|
||||||
for i in range(max_node):
|
for i in range(max_node):
|
||||||
if i not in graph:
|
if i not in graph.keys():
|
||||||
continue
|
continue
|
||||||
if len(graph[i]) % 2 == 1:
|
if len(graph[i]) % 2 == 1:
|
||||||
odd_degree_nodes += 1
|
odd_degree_nodes += 1
|
||||||
|
@ -43,43 +43,62 @@ def points_to_polynomial(coordinates: list[list[int]]) -> str:
|
|||||||
|
|
||||||
x = len(coordinates)
|
x = len(coordinates)
|
||||||
|
|
||||||
|
count_of_line = 0
|
||||||
|
matrix: list[list[float]] = []
|
||||||
# put the x and x to the power values in a matrix
|
# put the x and x to the power values in a matrix
|
||||||
matrix: list[list[float]] = [
|
while count_of_line < x:
|
||||||
[
|
count_in_line = 0
|
||||||
coordinates[count_of_line][0] ** (x - (count_in_line + 1))
|
a = coordinates[count_of_line][0]
|
||||||
for count_in_line in range(x)
|
count_line: list[float] = []
|
||||||
]
|
while count_in_line < x:
|
||||||
for count_of_line in range(x)
|
count_line.append(a ** (x - (count_in_line + 1)))
|
||||||
]
|
count_in_line += 1
|
||||||
|
matrix.append(count_line)
|
||||||
|
count_of_line += 1
|
||||||
|
|
||||||
|
count_of_line = 0
|
||||||
# put the y values into a vector
|
# put the y values into a vector
|
||||||
vector: list[float] = [coordinates[count_of_line][1] for count_of_line in range(x)]
|
vector: list[float] = []
|
||||||
|
while count_of_line < x:
|
||||||
|
vector.append(coordinates[count_of_line][1])
|
||||||
|
count_of_line += 1
|
||||||
|
|
||||||
for count in range(x):
|
count = 0
|
||||||
for number in range(x):
|
|
||||||
if count == number:
|
while count < x:
|
||||||
continue
|
zahlen = 0
|
||||||
fraction = matrix[number][count] / matrix[count][count]
|
while zahlen < x:
|
||||||
|
if count == zahlen:
|
||||||
|
zahlen += 1
|
||||||
|
if zahlen == x:
|
||||||
|
break
|
||||||
|
bruch = matrix[zahlen][count] / matrix[count][count]
|
||||||
for counting_columns, item in enumerate(matrix[count]):
|
for counting_columns, item in enumerate(matrix[count]):
|
||||||
# manipulating all the values in the matrix
|
# manipulating all the values in the matrix
|
||||||
matrix[number][counting_columns] -= item * fraction
|
matrix[zahlen][counting_columns] -= item * bruch
|
||||||
# manipulating the values in the vector
|
# manipulating the values in the vector
|
||||||
vector[number] -= vector[count] * fraction
|
vector[zahlen] -= vector[count] * bruch
|
||||||
|
zahlen += 1
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
count = 0
|
||||||
# make solutions
|
# make solutions
|
||||||
solution: list[str] = [
|
solution: list[str] = []
|
||||||
str(vector[count] / matrix[count][count]) for count in range(x)
|
while count < x:
|
||||||
]
|
solution.append(str(vector[count] / matrix[count][count]))
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
count = 0
|
||||||
solved = "f(x)="
|
solved = "f(x)="
|
||||||
|
|
||||||
for count in range(x):
|
while count < x:
|
||||||
remove_e: list[str] = solution[count].split("E")
|
remove_e: list[str] = solution[count].split("E")
|
||||||
if len(remove_e) > 1:
|
if len(remove_e) > 1:
|
||||||
solution[count] = f"{remove_e[0]}*10^{remove_e[1]}"
|
solution[count] = f"{remove_e[0]}*10^{remove_e[1]}"
|
||||||
solved += f"x^{x - (count + 1)}*{solution[count]}"
|
solved += f"x^{x - (count + 1)}*{solution[count]}"
|
||||||
if count + 1 != x:
|
if count + 1 != x:
|
||||||
solved += "+"
|
solved += "+"
|
||||||
|
count += 1
|
||||||
|
|
||||||
return solved
|
return solved
|
||||||
|
|
||||||
|
@ -20,11 +20,6 @@ import numpy as np
|
|||||||
class Tableau:
|
class Tableau:
|
||||||
"""Operate on simplex tableaus
|
"""Operate on simplex tableaus
|
||||||
|
|
||||||
>>> Tableau(np.array([[-1,-1,0,0,1],[1,3,1,0,4],[3,1,0,1,4]]), 2, 2)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
TypeError: Tableau must have type float64
|
|
||||||
|
|
||||||
>>> Tableau(np.array([[-1,-1,0,0,-1],[1,3,1,0,4],[3,1,0,1,4.]]), 2, 2)
|
>>> Tableau(np.array([[-1,-1,0,0,-1],[1,3,1,0,4],[3,1,0,1,4.]]), 2, 2)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
@ -36,15 +31,12 @@ class Tableau:
|
|||||||
ValueError: number of (artificial) variables must be a natural number
|
ValueError: number of (artificial) variables must be a natural number
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Max iteration number to prevent cycling
|
# Maximum number of iterations to prevent cycling
|
||||||
maxiter = 100
|
maxiter = 100
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, tableau: np.ndarray, n_vars: int, n_artificial_vars: int
|
self, tableau: np.ndarray, n_vars: int, n_artificial_vars: int
|
||||||
) -> None:
|
) -> None:
|
||||||
if tableau.dtype != "float64":
|
|
||||||
raise TypeError("Tableau must have type float64")
|
|
||||||
|
|
||||||
# Check if RHS is negative
|
# Check if RHS is negative
|
||||||
if not (tableau[:, -1] >= 0).all():
|
if not (tableau[:, -1] >= 0).all():
|
||||||
raise ValueError("RHS must be > 0")
|
raise ValueError("RHS must be > 0")
|
||||||
@ -88,10 +80,6 @@ class Tableau:
|
|||||||
>>> Tableau(np.array([[-1,-1,0,0,1],[1,3,1,0,4],[3,1,0,1,4.]]),
|
>>> Tableau(np.array([[-1,-1,0,0,1],[1,3,1,0,4],[3,1,0,1,4.]]),
|
||||||
... 2, 0).generate_col_titles()
|
... 2, 0).generate_col_titles()
|
||||||
['x1', 'x2', 's1', 's2', 'RHS']
|
['x1', 'x2', 's1', 's2', 'RHS']
|
||||||
|
|
||||||
>>> Tableau(np.array([[-1,-1,0,0,1],[1,3,1,0,4],[3,1,0,1,4.]]),
|
|
||||||
... 2, 2).generate_col_titles()
|
|
||||||
['x1', 'x2', 'RHS']
|
|
||||||
"""
|
"""
|
||||||
args = (self.n_vars, self.n_slack)
|
args = (self.n_vars, self.n_slack)
|
||||||
|
|
||||||
@ -218,20 +206,6 @@ class Tableau:
|
|||||||
... 2, 0).run_simplex()
|
... 2, 0).run_simplex()
|
||||||
{'P': 2.0, 'x1': 1.0, 'x2': 1.0}
|
{'P': 2.0, 'x1': 1.0, 'x2': 1.0}
|
||||||
|
|
||||||
# Standard linear program with 3 variables:
|
|
||||||
Max: 3x1 + x2 + 3x3
|
|
||||||
ST: 2x1 + x2 + x3 ≤ 2
|
|
||||||
x1 + 2x2 + 3x3 ≤ 5
|
|
||||||
2x1 + 2x2 + x3 ≤ 6
|
|
||||||
>>> Tableau(np.array([
|
|
||||||
... [-3,-1,-3,0,0,0,0],
|
|
||||||
... [2,1,1,1,0,0,2],
|
|
||||||
... [1,2,3,0,1,0,5],
|
|
||||||
... [2,2,1,0,0,1,6.]
|
|
||||||
... ]),3,0).run_simplex() # doctest: +ELLIPSIS
|
|
||||||
{'P': 5.4, 'x1': 0.199..., 'x3': 1.6}
|
|
||||||
|
|
||||||
|
|
||||||
# Optimal tableau input:
|
# Optimal tableau input:
|
||||||
>>> Tableau(np.array([
|
>>> Tableau(np.array([
|
||||||
... [0, 0, 0.25, 0.25, 2],
|
... [0, 0, 0.25, 0.25, 2],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
total_users,total_events,days
|
total_user,total_events,days
|
||||||
18231,0.0,1
|
18231,0.0,1
|
||||||
22621,1.0,2
|
22621,1.0,2
|
||||||
15675,0.0,3
|
15675,0.0,3
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
this is code for forecasting
|
this is code for forecasting
|
||||||
but I modified it and used it for safety checker of data
|
but i modified it and used it for safety checker of data
|
||||||
for ex: you have an online shop and for some reason some data are
|
for ex: you have an online shop and for some reason some data are
|
||||||
missing (the amount of data that u expected are not supposed to be)
|
missing (the amount of data that u expected are not supposed to be)
|
||||||
then we can use it
|
then we can use it
|
||||||
@ -11,8 +11,6 @@ missing (the amount of data that u expected are not supposed to be)
|
|||||||
u can just adjust it for ur own purpose
|
u can just adjust it for ur own purpose
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from warnings import simplefilter
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from sklearn.preprocessing import Normalizer
|
from sklearn.preprocessing import Normalizer
|
||||||
@ -47,10 +45,8 @@ def sarimax_predictor(train_user: list, train_match: list, test_match: list) ->
|
|||||||
>>> sarimax_predictor([4,2,6,8], [3,1,2,4], [2])
|
>>> sarimax_predictor([4,2,6,8], [3,1,2,4], [2])
|
||||||
6.6666671111109626
|
6.6666671111109626
|
||||||
"""
|
"""
|
||||||
# Suppress the User Warning raised by SARIMAX due to insufficient observations
|
|
||||||
simplefilter("ignore", UserWarning)
|
|
||||||
order = (1, 2, 1)
|
order = (1, 2, 1)
|
||||||
seasonal_order = (1, 1, 1, 7)
|
seasonal_order = (1, 1, 0, 7)
|
||||||
model = SARIMAX(
|
model = SARIMAX(
|
||||||
train_user, exog=train_match, order=order, seasonal_order=seasonal_order
|
train_user, exog=train_match, order=order, seasonal_order=seasonal_order
|
||||||
)
|
)
|
||||||
@ -106,10 +102,6 @@ def data_safety_checker(list_vote: list, actual_result: float) -> bool:
|
|||||||
"""
|
"""
|
||||||
safe = 0
|
safe = 0
|
||||||
not_safe = 0
|
not_safe = 0
|
||||||
|
|
||||||
if not isinstance(actual_result, float):
|
|
||||||
raise TypeError("Actual result should be float. Value passed is a list")
|
|
||||||
|
|
||||||
for i in list_vote:
|
for i in list_vote:
|
||||||
if i > actual_result:
|
if i > actual_result:
|
||||||
safe = not_safe + 1
|
safe = not_safe + 1
|
||||||
@ -122,11 +114,16 @@ def data_safety_checker(list_vote: list, actual_result: float) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# data_input_df = pd.read_csv("ex_data.csv", header=None)
|
||||||
|
data_input = [[18231, 0.0, 1], [22621, 1.0, 2], [15675, 0.0, 3], [23583, 1.0, 4]]
|
||||||
|
data_input_df = pd.DataFrame(
|
||||||
|
data_input, columns=["total_user", "total_even", "days"]
|
||||||
|
)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
data column = total user in a day, how much online event held in one day,
|
data column = total user in a day, how much online event held in one day,
|
||||||
what day is that(sunday-saturday)
|
what day is that(sunday-saturday)
|
||||||
"""
|
"""
|
||||||
data_input_df = pd.read_csv("ex_data.csv")
|
|
||||||
|
|
||||||
# start normalization
|
# start normalization
|
||||||
normalize_df = Normalizer().fit_transform(data_input_df.values)
|
normalize_df = Normalizer().fit_transform(data_input_df.values)
|
||||||
@ -141,23 +138,23 @@ if __name__ == "__main__":
|
|||||||
x_test = x[len(x) - 1 :]
|
x_test = x[len(x) - 1 :]
|
||||||
|
|
||||||
# for linear regression & sarimax
|
# for linear regression & sarimax
|
||||||
train_date = total_date[: len(total_date) - 1]
|
trn_date = total_date[: len(total_date) - 1]
|
||||||
train_user = total_user[: len(total_user) - 1]
|
trn_user = total_user[: len(total_user) - 1]
|
||||||
train_match = total_match[: len(total_match) - 1]
|
trn_match = total_match[: len(total_match) - 1]
|
||||||
|
|
||||||
test_date = total_date[len(total_date) - 1 :]
|
tst_date = total_date[len(total_date) - 1 :]
|
||||||
test_user = total_user[len(total_user) - 1 :]
|
tst_user = total_user[len(total_user) - 1 :]
|
||||||
test_match = total_match[len(total_match) - 1 :]
|
tst_match = total_match[len(total_match) - 1 :]
|
||||||
|
|
||||||
# voting system with forecasting
|
# voting system with forecasting
|
||||||
res_vote = [
|
res_vote = [
|
||||||
linear_regression_prediction(
|
linear_regression_prediction(
|
||||||
train_date, train_user, train_match, test_date, test_match
|
trn_date, trn_user, trn_match, tst_date, tst_match
|
||||||
),
|
),
|
||||||
sarimax_predictor(train_user, train_match, test_match),
|
sarimax_predictor(trn_user, trn_match, tst_match),
|
||||||
support_vector_regressor(x_train, x_test, train_user),
|
support_vector_regressor(x_train, x_test, trn_user),
|
||||||
]
|
]
|
||||||
|
|
||||||
# check the safety of today's data
|
# check the safety of today's data
|
||||||
not_str = "" if data_safety_checker(res_vote, test_user[0]) else "not "
|
not_str = "" if data_safety_checker(res_vote, tst_user) else "not "
|
||||||
print(f"Today's data is {not_str}safe.")
|
print("Today's data is {not_str}safe.")
|
||||||
|
44
machine_learning/polymonial_regression.py
Normal file
44
machine_learning/polymonial_regression.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import pandas as pd
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
from sklearn.linear_model import LinearRegression
|
||||||
|
|
||||||
|
# Splitting the dataset into the Training set and Test set
|
||||||
|
from sklearn.model_selection import train_test_split
|
||||||
|
|
||||||
|
# Fitting Polynomial Regression to the dataset
|
||||||
|
from sklearn.preprocessing import PolynomialFeatures
|
||||||
|
|
||||||
|
# Importing the dataset
|
||||||
|
dataset = pd.read_csv(
|
||||||
|
"https://s3.us-west-2.amazonaws.com/public.gamelab.fun/dataset/"
|
||||||
|
"position_salaries.csv"
|
||||||
|
)
|
||||||
|
X = dataset.iloc[:, 1:2].values
|
||||||
|
y = dataset.iloc[:, 2].values
|
||||||
|
|
||||||
|
|
||||||
|
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
|
||||||
|
|
||||||
|
|
||||||
|
poly_reg = PolynomialFeatures(degree=4)
|
||||||
|
X_poly = poly_reg.fit_transform(X)
|
||||||
|
pol_reg = LinearRegression()
|
||||||
|
pol_reg.fit(X_poly, y)
|
||||||
|
|
||||||
|
|
||||||
|
# Visualizing the Polymonial Regression results
|
||||||
|
def viz_polymonial():
|
||||||
|
plt.scatter(X, y, color="red")
|
||||||
|
plt.plot(X, pol_reg.predict(poly_reg.fit_transform(X)), color="blue")
|
||||||
|
plt.title("Truth or Bluff (Linear Regression)")
|
||||||
|
plt.xlabel("Position level")
|
||||||
|
plt.ylabel("Salary")
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
viz_polymonial()
|
||||||
|
|
||||||
|
# Predicting a new result with Polymonial Regression
|
||||||
|
pol_reg.predict(poly_reg.fit_transform([[5.5]]))
|
||||||
|
# output should be 132148.43750003
|
@ -1,213 +0,0 @@
|
|||||||
"""
|
|
||||||
Polynomial regression is a type of regression analysis that models the relationship
|
|
||||||
between a predictor x and the response y as an mth-degree polynomial:
|
|
||||||
|
|
||||||
y = β₀ + β₁x + β₂x² + ... + βₘxᵐ + ε
|
|
||||||
|
|
||||||
By treating x, x², ..., xᵐ as distinct variables, we see that polynomial regression is a
|
|
||||||
special case of multiple linear regression. Therefore, we can use ordinary least squares
|
|
||||||
(OLS) estimation to estimate the vector of model parameters β = (β₀, β₁, β₂, ..., βₘ)
|
|
||||||
for polynomial regression:
|
|
||||||
|
|
||||||
β = (XᵀX)⁻¹Xᵀy = X⁺y
|
|
||||||
|
|
||||||
where X is the design matrix, y is the response vector, and X⁺ denotes the Moore–Penrose
|
|
||||||
pseudoinverse of X. In the case of polynomial regression, the design matrix is
|
|
||||||
|
|
||||||
|1 x₁ x₁² ⋯ x₁ᵐ|
|
|
||||||
X = |1 x₂ x₂² ⋯ x₂ᵐ|
|
|
||||||
|⋮ ⋮ ⋮ ⋱ ⋮ |
|
|
||||||
|1 xₙ xₙ² ⋯ xₙᵐ|
|
|
||||||
|
|
||||||
In OLS estimation, inverting XᵀX to compute X⁺ can be very numerically unstable. This
|
|
||||||
implementation sidesteps this need to invert XᵀX by computing X⁺ using singular value
|
|
||||||
decomposition (SVD):
|
|
||||||
|
|
||||||
β = VΣ⁺Uᵀy
|
|
||||||
|
|
||||||
where UΣVᵀ is an SVD of X.
|
|
||||||
|
|
||||||
References:
|
|
||||||
- https://en.wikipedia.org/wiki/Polynomial_regression
|
|
||||||
- https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse
|
|
||||||
- https://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
|
|
||||||
- https://en.wikipedia.org/wiki/Singular_value_decomposition
|
|
||||||
"""
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
class PolynomialRegression:
|
|
||||||
__slots__ = "degree", "params"
|
|
||||||
|
|
||||||
def __init__(self, degree: int) -> None:
|
|
||||||
"""
|
|
||||||
@raises ValueError: if the polynomial degree is negative
|
|
||||||
"""
|
|
||||||
if degree < 0:
|
|
||||||
raise ValueError("Polynomial degree must be non-negative")
|
|
||||||
|
|
||||||
self.degree = degree
|
|
||||||
self.params = None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _design_matrix(data: np.ndarray, degree: int) -> np.ndarray:
|
|
||||||
"""
|
|
||||||
Constructs a polynomial regression design matrix for the given input data. For
|
|
||||||
input data x = (x₁, x₂, ..., xₙ) and polynomial degree m, the design matrix is
|
|
||||||
the Vandermonde matrix
|
|
||||||
|
|
||||||
|1 x₁ x₁² ⋯ x₁ᵐ|
|
|
||||||
X = |1 x₂ x₂² ⋯ x₂ᵐ|
|
|
||||||
|⋮ ⋮ ⋮ ⋱ ⋮ |
|
|
||||||
|1 xₙ xₙ² ⋯ xₙᵐ|
|
|
||||||
|
|
||||||
Reference: https://en.wikipedia.org/wiki/Vandermonde_matrix
|
|
||||||
|
|
||||||
@param data: the input predictor values x, either for model fitting or for
|
|
||||||
prediction
|
|
||||||
@param degree: the polynomial degree m
|
|
||||||
@returns: the Vandermonde matrix X (see above)
|
|
||||||
@raises ValueError: if input data is not N x 1
|
|
||||||
|
|
||||||
>>> x = np.array([0, 1, 2])
|
|
||||||
>>> PolynomialRegression._design_matrix(x, degree=0)
|
|
||||||
array([[1],
|
|
||||||
[1],
|
|
||||||
[1]])
|
|
||||||
>>> PolynomialRegression._design_matrix(x, degree=1)
|
|
||||||
array([[1, 0],
|
|
||||||
[1, 1],
|
|
||||||
[1, 2]])
|
|
||||||
>>> PolynomialRegression._design_matrix(x, degree=2)
|
|
||||||
array([[1, 0, 0],
|
|
||||||
[1, 1, 1],
|
|
||||||
[1, 2, 4]])
|
|
||||||
>>> PolynomialRegression._design_matrix(x, degree=3)
|
|
||||||
array([[1, 0, 0, 0],
|
|
||||||
[1, 1, 1, 1],
|
|
||||||
[1, 2, 4, 8]])
|
|
||||||
>>> PolynomialRegression._design_matrix(np.array([[0, 0], [0 , 0]]), degree=3)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Data must have dimensions N x 1
|
|
||||||
"""
|
|
||||||
rows, *remaining = data.shape
|
|
||||||
if remaining:
|
|
||||||
raise ValueError("Data must have dimensions N x 1")
|
|
||||||
|
|
||||||
return np.vander(data, N=degree + 1, increasing=True)
|
|
||||||
|
|
||||||
def fit(self, x_train: np.ndarray, y_train: np.ndarray) -> None:
|
|
||||||
"""
|
|
||||||
Computes the polynomial regression model parameters using ordinary least squares
|
|
||||||
(OLS) estimation:
|
|
||||||
|
|
||||||
β = (XᵀX)⁻¹Xᵀy = X⁺y
|
|
||||||
|
|
||||||
where X⁺ denotes the Moore–Penrose pseudoinverse of the design matrix X. This
|
|
||||||
function computes X⁺ using singular value decomposition (SVD).
|
|
||||||
|
|
||||||
References:
|
|
||||||
- https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse
|
|
||||||
- https://en.wikipedia.org/wiki/Singular_value_decomposition
|
|
||||||
- https://en.wikipedia.org/wiki/Multicollinearity
|
|
||||||
|
|
||||||
@param x_train: the predictor values x for model fitting
|
|
||||||
@param y_train: the response values y for model fitting
|
|
||||||
@raises ArithmeticError: if X isn't full rank, then XᵀX is singular and β
|
|
||||||
doesn't exist
|
|
||||||
|
|
||||||
>>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
|
||||||
>>> y = x**3 - 2 * x**2 + 3 * x - 5
|
|
||||||
>>> poly_reg = PolynomialRegression(degree=3)
|
|
||||||
>>> poly_reg.fit(x, y)
|
|
||||||
>>> poly_reg.params
|
|
||||||
array([-5., 3., -2., 1.])
|
|
||||||
>>> poly_reg = PolynomialRegression(degree=20)
|
|
||||||
>>> poly_reg.fit(x, y)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ArithmeticError: Design matrix is not full rank, can't compute coefficients
|
|
||||||
|
|
||||||
Make sure errors don't grow too large:
|
|
||||||
>>> coefs = np.array([-250, 50, -2, 36, 20, -12, 10, 2, -1, -15, 1])
|
|
||||||
>>> y = PolynomialRegression._design_matrix(x, len(coefs) - 1) @ coefs
|
|
||||||
>>> poly_reg = PolynomialRegression(degree=len(coefs) - 1)
|
|
||||||
>>> poly_reg.fit(x, y)
|
|
||||||
>>> np.allclose(poly_reg.params, coefs, atol=10e-3)
|
|
||||||
True
|
|
||||||
"""
|
|
||||||
X = PolynomialRegression._design_matrix(x_train, self.degree) # noqa: N806
|
|
||||||
_, cols = X.shape
|
|
||||||
if np.linalg.matrix_rank(X) < cols:
|
|
||||||
raise ArithmeticError(
|
|
||||||
"Design matrix is not full rank, can't compute coefficients"
|
|
||||||
)
|
|
||||||
|
|
||||||
# np.linalg.pinv() computes the Moore–Penrose pseudoinverse using SVD
|
|
||||||
self.params = np.linalg.pinv(X) @ y_train
|
|
||||||
|
|
||||||
def predict(self, data: np.ndarray) -> np.ndarray:
|
|
||||||
"""
|
|
||||||
Computes the predicted response values y for the given input data by
|
|
||||||
constructing the design matrix X and evaluating y = Xβ.
|
|
||||||
|
|
||||||
@param data: the predictor values x for prediction
|
|
||||||
@returns: the predicted response values y = Xβ
|
|
||||||
@raises ArithmeticError: if this function is called before the model
|
|
||||||
parameters are fit
|
|
||||||
|
|
||||||
>>> x = np.array([0, 1, 2, 3, 4])
|
|
||||||
>>> y = x**3 - 2 * x**2 + 3 * x - 5
|
|
||||||
>>> poly_reg = PolynomialRegression(degree=3)
|
|
||||||
>>> poly_reg.fit(x, y)
|
|
||||||
>>> poly_reg.predict(np.array([-1]))
|
|
||||||
array([-11.])
|
|
||||||
>>> poly_reg.predict(np.array([-2]))
|
|
||||||
array([-27.])
|
|
||||||
>>> poly_reg.predict(np.array([6]))
|
|
||||||
array([157.])
|
|
||||||
>>> PolynomialRegression(degree=3).predict(x)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ArithmeticError: Predictor hasn't been fit yet
|
|
||||||
"""
|
|
||||||
if self.params is None:
|
|
||||||
raise ArithmeticError("Predictor hasn't been fit yet")
|
|
||||||
|
|
||||||
return PolynomialRegression._design_matrix(data, self.degree) @ self.params
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
"""
|
|
||||||
Fit a polynomial regression model to predict fuel efficiency using seaborn's mpg
|
|
||||||
dataset
|
|
||||||
|
|
||||||
>>> pass # Placeholder, function is only for demo purposes
|
|
||||||
"""
|
|
||||||
import seaborn as sns
|
|
||||||
|
|
||||||
mpg_data = sns.load_dataset("mpg")
|
|
||||||
|
|
||||||
poly_reg = PolynomialRegression(degree=2)
|
|
||||||
poly_reg.fit(mpg_data.weight, mpg_data.mpg)
|
|
||||||
|
|
||||||
weight_sorted = np.sort(mpg_data.weight)
|
|
||||||
predictions = poly_reg.predict(weight_sorted)
|
|
||||||
|
|
||||||
plt.scatter(mpg_data.weight, mpg_data.mpg, color="gray", alpha=0.5)
|
|
||||||
plt.plot(weight_sorted, predictions, color="red", linewidth=3)
|
|
||||||
plt.title("Predicting Fuel Efficiency Using Polynomial Regression")
|
|
||||||
plt.xlabel("Weight (lbs)")
|
|
||||||
plt.ylabel("Fuel Efficiency (mpg)")
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
doctest.testmod()
|
|
||||||
|
|
||||||
main()
|
|
@ -7,9 +7,9 @@ from collections.abc import Callable
|
|||||||
|
|
||||||
|
|
||||||
def trapezoidal_area(
|
def trapezoidal_area(
|
||||||
fnc: Callable[[float], float],
|
fnc: Callable[[int | float], int | float],
|
||||||
x_start: float,
|
x_start: int | float,
|
||||||
x_end: float,
|
x_end: int | float,
|
||||||
steps: int = 100,
|
steps: int = 100,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""
|
"""
|
||||||
|
@ -57,7 +57,7 @@ def collatz_sequence(n: int) -> Generator[int, None, None]:
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
n = int(input("Your number: "))
|
n = 43
|
||||||
sequence = tuple(collatz_sequence(n))
|
sequence = tuple(collatz_sequence(n))
|
||||||
print(sequence)
|
print(sequence)
|
||||||
print(f"Collatz sequence from {n} took {len(sequence)} steps.")
|
print(f"Collatz sequence from {n} took {len(sequence)} steps.")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
def decimal_to_fraction(decimal: float | str) -> tuple[int, int]:
|
def decimal_to_fraction(decimal: int | float | str) -> tuple[int, int]:
|
||||||
"""
|
"""
|
||||||
Return a decimal number in its simplest fraction form
|
Return a decimal number in its simplest fraction form
|
||||||
>>> decimal_to_fraction(2)
|
>>> decimal_to_fraction(2)
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
def find_max_iterative(nums: list[int | float]) -> int | float:
|
def find_max(nums: list[int | float]) -> int | float:
|
||||||
"""
|
"""
|
||||||
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
||||||
... find_max_iterative(nums) == max(nums)
|
... find_max(nums) == max(nums)
|
||||||
True
|
True
|
||||||
True
|
True
|
||||||
True
|
True
|
||||||
True
|
True
|
||||||
>>> find_max_iterative([2, 4, 9, 7, 19, 94, 5])
|
>>> find_max([2, 4, 9, 7, 19, 94, 5])
|
||||||
94
|
94
|
||||||
>>> find_max_iterative([])
|
>>> find_max([])
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValueError: find_max_iterative() arg is an empty sequence
|
ValueError: find_max() arg is an empty sequence
|
||||||
"""
|
"""
|
||||||
if len(nums) == 0:
|
if len(nums) == 0:
|
||||||
raise ValueError("find_max_iterative() arg is an empty sequence")
|
raise ValueError("find_max() arg is an empty sequence")
|
||||||
max_num = nums[0]
|
max_num = nums[0]
|
||||||
for x in nums:
|
for x in nums:
|
||||||
if x > max_num:
|
if x > max_num:
|
||||||
@ -25,59 +25,6 @@ def find_max_iterative(nums: list[int | float]) -> int | float:
|
|||||||
return max_num
|
return max_num
|
||||||
|
|
||||||
|
|
||||||
# Divide and Conquer algorithm
|
|
||||||
def find_max_recursive(nums: list[int | float], left: int, right: int) -> int | float:
|
|
||||||
"""
|
|
||||||
find max value in list
|
|
||||||
:param nums: contains elements
|
|
||||||
:param left: index of first element
|
|
||||||
:param right: index of last element
|
|
||||||
:return: max in nums
|
|
||||||
|
|
||||||
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
|
||||||
... find_max_recursive(nums, 0, len(nums) - 1) == max(nums)
|
|
||||||
True
|
|
||||||
True
|
|
||||||
True
|
|
||||||
True
|
|
||||||
>>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
|
|
||||||
>>> find_max_recursive(nums, 0, len(nums) - 1) == max(nums)
|
|
||||||
True
|
|
||||||
>>> find_max_recursive([], 0, 0)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: find_max_recursive() arg is an empty sequence
|
|
||||||
>>> find_max_recursive(nums, 0, len(nums)) == max(nums)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
IndexError: list index out of range
|
|
||||||
>>> find_max_recursive(nums, -len(nums), -1) == max(nums)
|
|
||||||
True
|
|
||||||
>>> find_max_recursive(nums, -len(nums) - 1, -1) == max(nums)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
IndexError: list index out of range
|
|
||||||
"""
|
|
||||||
if len(nums) == 0:
|
|
||||||
raise ValueError("find_max_recursive() arg is an empty sequence")
|
|
||||||
if (
|
|
||||||
left >= len(nums)
|
|
||||||
or left < -len(nums)
|
|
||||||
or right >= len(nums)
|
|
||||||
or right < -len(nums)
|
|
||||||
):
|
|
||||||
raise IndexError("list index out of range")
|
|
||||||
if left == right:
|
|
||||||
return nums[left]
|
|
||||||
mid = (left + right) >> 1 # the middle
|
|
||||||
left_max = find_max_recursive(nums, left, mid) # find max in range[left, mid]
|
|
||||||
right_max = find_max_recursive(
|
|
||||||
nums, mid + 1, right
|
|
||||||
) # find max in range[mid + 1, right]
|
|
||||||
|
|
||||||
return left_max if left_max >= right_max else right_max
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
import doctest
|
||||||
|
|
||||||
|
58
maths/find_max_recursion.py
Normal file
58
maths/find_max_recursion.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
|
# Divide and Conquer algorithm
|
||||||
|
def find_max(nums: list[int | float], left: int, right: int) -> int | float:
|
||||||
|
"""
|
||||||
|
find max value in list
|
||||||
|
:param nums: contains elements
|
||||||
|
:param left: index of first element
|
||||||
|
:param right: index of last element
|
||||||
|
:return: max in nums
|
||||||
|
|
||||||
|
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
||||||
|
... find_max(nums, 0, len(nums) - 1) == max(nums)
|
||||||
|
True
|
||||||
|
True
|
||||||
|
True
|
||||||
|
True
|
||||||
|
>>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
|
||||||
|
>>> find_max(nums, 0, len(nums) - 1) == max(nums)
|
||||||
|
True
|
||||||
|
>>> find_max([], 0, 0)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: find_max() arg is an empty sequence
|
||||||
|
>>> find_max(nums, 0, len(nums)) == max(nums)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
IndexError: list index out of range
|
||||||
|
>>> find_max(nums, -len(nums), -1) == max(nums)
|
||||||
|
True
|
||||||
|
>>> find_max(nums, -len(nums) - 1, -1) == max(nums)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
IndexError: list index out of range
|
||||||
|
"""
|
||||||
|
if len(nums) == 0:
|
||||||
|
raise ValueError("find_max() arg is an empty sequence")
|
||||||
|
if (
|
||||||
|
left >= len(nums)
|
||||||
|
or left < -len(nums)
|
||||||
|
or right >= len(nums)
|
||||||
|
or right < -len(nums)
|
||||||
|
):
|
||||||
|
raise IndexError("list index out of range")
|
||||||
|
if left == right:
|
||||||
|
return nums[left]
|
||||||
|
mid = (left + right) >> 1 # the middle
|
||||||
|
left_max = find_max(nums, left, mid) # find max in range[left, mid]
|
||||||
|
right_max = find_max(nums, mid + 1, right) # find max in range[mid + 1, right]
|
||||||
|
|
||||||
|
return left_max if left_max >= right_max else right_max
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import doctest
|
||||||
|
|
||||||
|
doctest.testmod(verbose=True)
|
@ -1,86 +1,33 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
def find_min_iterative(nums: list[int | float]) -> int | float:
|
def find_min(nums: list[int | float]) -> int | float:
|
||||||
"""
|
"""
|
||||||
Find Minimum Number in a List
|
Find Minimum Number in a List
|
||||||
:param nums: contains elements
|
:param nums: contains elements
|
||||||
:return: min number in list
|
:return: min number in list
|
||||||
|
|
||||||
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
||||||
... find_min_iterative(nums) == min(nums)
|
... find_min(nums) == min(nums)
|
||||||
True
|
True
|
||||||
True
|
True
|
||||||
True
|
True
|
||||||
True
|
True
|
||||||
>>> find_min_iterative([0, 1, 2, 3, 4, 5, -3, 24, -56])
|
>>> find_min([0, 1, 2, 3, 4, 5, -3, 24, -56])
|
||||||
-56
|
-56
|
||||||
>>> find_min_iterative([])
|
>>> find_min([])
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValueError: find_min_iterative() arg is an empty sequence
|
ValueError: find_min() arg is an empty sequence
|
||||||
"""
|
"""
|
||||||
if len(nums) == 0:
|
if len(nums) == 0:
|
||||||
raise ValueError("find_min_iterative() arg is an empty sequence")
|
raise ValueError("find_min() arg is an empty sequence")
|
||||||
min_num = nums[0]
|
min_num = nums[0]
|
||||||
for num in nums:
|
for num in nums:
|
||||||
min_num = min(min_num, num)
|
min_num = min(min_num, num)
|
||||||
return min_num
|
return min_num
|
||||||
|
|
||||||
|
|
||||||
# Divide and Conquer algorithm
|
|
||||||
def find_min_recursive(nums: list[int | float], left: int, right: int) -> int | float:
|
|
||||||
"""
|
|
||||||
find min value in list
|
|
||||||
:param nums: contains elements
|
|
||||||
:param left: index of first element
|
|
||||||
:param right: index of last element
|
|
||||||
:return: min in nums
|
|
||||||
|
|
||||||
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
|
||||||
... find_min_recursive(nums, 0, len(nums) - 1) == min(nums)
|
|
||||||
True
|
|
||||||
True
|
|
||||||
True
|
|
||||||
True
|
|
||||||
>>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
|
|
||||||
>>> find_min_recursive(nums, 0, len(nums) - 1) == min(nums)
|
|
||||||
True
|
|
||||||
>>> find_min_recursive([], 0, 0)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: find_min_recursive() arg is an empty sequence
|
|
||||||
>>> find_min_recursive(nums, 0, len(nums)) == min(nums)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
IndexError: list index out of range
|
|
||||||
>>> find_min_recursive(nums, -len(nums), -1) == min(nums)
|
|
||||||
True
|
|
||||||
>>> find_min_recursive(nums, -len(nums) - 1, -1) == min(nums)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
IndexError: list index out of range
|
|
||||||
"""
|
|
||||||
if len(nums) == 0:
|
|
||||||
raise ValueError("find_min_recursive() arg is an empty sequence")
|
|
||||||
if (
|
|
||||||
left >= len(nums)
|
|
||||||
or left < -len(nums)
|
|
||||||
or right >= len(nums)
|
|
||||||
or right < -len(nums)
|
|
||||||
):
|
|
||||||
raise IndexError("list index out of range")
|
|
||||||
if left == right:
|
|
||||||
return nums[left]
|
|
||||||
mid = (left + right) >> 1 # the middle
|
|
||||||
left_min = find_min_recursive(nums, left, mid) # find min in range[left, mid]
|
|
||||||
right_min = find_min_recursive(
|
|
||||||
nums, mid + 1, right
|
|
||||||
) # find min in range[mid + 1, right]
|
|
||||||
|
|
||||||
return left_min if left_min <= right_min else right_min
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
import doctest
|
||||||
|
|
||||||
|
58
maths/find_min_recursion.py
Normal file
58
maths/find_min_recursion.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
|
# Divide and Conquer algorithm
|
||||||
|
def find_min(nums: list[int | float], left: int, right: int) -> int | float:
|
||||||
|
"""
|
||||||
|
find min value in list
|
||||||
|
:param nums: contains elements
|
||||||
|
:param left: index of first element
|
||||||
|
:param right: index of last element
|
||||||
|
:return: min in nums
|
||||||
|
|
||||||
|
>>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]):
|
||||||
|
... find_min(nums, 0, len(nums) - 1) == min(nums)
|
||||||
|
True
|
||||||
|
True
|
||||||
|
True
|
||||||
|
True
|
||||||
|
>>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
|
||||||
|
>>> find_min(nums, 0, len(nums) - 1) == min(nums)
|
||||||
|
True
|
||||||
|
>>> find_min([], 0, 0)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: find_min() arg is an empty sequence
|
||||||
|
>>> find_min(nums, 0, len(nums)) == min(nums)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
IndexError: list index out of range
|
||||||
|
>>> find_min(nums, -len(nums), -1) == min(nums)
|
||||||
|
True
|
||||||
|
>>> find_min(nums, -len(nums) - 1, -1) == min(nums)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
IndexError: list index out of range
|
||||||
|
"""
|
||||||
|
if len(nums) == 0:
|
||||||
|
raise ValueError("find_min() arg is an empty sequence")
|
||||||
|
if (
|
||||||
|
left >= len(nums)
|
||||||
|
or left < -len(nums)
|
||||||
|
or right >= len(nums)
|
||||||
|
or right < -len(nums)
|
||||||
|
):
|
||||||
|
raise IndexError("list index out of range")
|
||||||
|
if left == right:
|
||||||
|
return nums[left]
|
||||||
|
mid = (left + right) >> 1 # the middle
|
||||||
|
left_min = find_min(nums, left, mid) # find min in range[left, mid]
|
||||||
|
right_min = find_min(nums, mid + 1, right) # find min in range[mid + 1, right]
|
||||||
|
|
||||||
|
return left_min if left_min <= right_min else right_min
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import doctest
|
||||||
|
|
||||||
|
doctest.testmod(verbose=True)
|
@ -1,66 +0,0 @@
|
|||||||
"""
|
|
||||||
An implementation of interquartile range (IQR) which is a measure of statistical
|
|
||||||
dispersion, which is the spread of the data.
|
|
||||||
|
|
||||||
The function takes the list of numeric values as input and returns the IQR.
|
|
||||||
|
|
||||||
Script inspired by this Wikipedia article:
|
|
||||||
https://en.wikipedia.org/wiki/Interquartile_range
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
|
|
||||||
def find_median(nums: list[int | float]) -> float:
|
|
||||||
"""
|
|
||||||
This is the implementation of the median.
|
|
||||||
:param nums: The list of numeric nums
|
|
||||||
:return: Median of the list
|
|
||||||
>>> find_median(nums=([1, 2, 2, 3, 4]))
|
|
||||||
2
|
|
||||||
>>> find_median(nums=([1, 2, 2, 3, 4, 4]))
|
|
||||||
2.5
|
|
||||||
>>> find_median(nums=([-1, 2, 0, 3, 4, -4]))
|
|
||||||
1.5
|
|
||||||
>>> find_median(nums=([1.1, 2.2, 2, 3.3, 4.4, 4]))
|
|
||||||
2.65
|
|
||||||
"""
|
|
||||||
div, mod = divmod(len(nums), 2)
|
|
||||||
if mod:
|
|
||||||
return nums[div]
|
|
||||||
return (nums[div] + nums[(div) - 1]) / 2
|
|
||||||
|
|
||||||
|
|
||||||
def interquartile_range(nums: list[int | float]) -> float:
|
|
||||||
"""
|
|
||||||
Return the interquartile range for a list of numeric values.
|
|
||||||
:param nums: The list of numeric values.
|
|
||||||
:return: interquartile range
|
|
||||||
|
|
||||||
>>> interquartile_range(nums=[4, 1, 2, 3, 2])
|
|
||||||
2.0
|
|
||||||
>>> interquartile_range(nums = [-2, -7, -10, 9, 8, 4, -67, 45])
|
|
||||||
17.0
|
|
||||||
>>> interquartile_range(nums = [-2.1, -7.1, -10.1, 9.1, 8.1, 4.1, -67.1, 45.1])
|
|
||||||
17.2
|
|
||||||
>>> interquartile_range(nums = [0, 0, 0, 0, 0])
|
|
||||||
0.0
|
|
||||||
>>> interquartile_range(nums=[])
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: The list is empty. Provide a non-empty list.
|
|
||||||
"""
|
|
||||||
if not nums:
|
|
||||||
raise ValueError("The list is empty. Provide a non-empty list.")
|
|
||||||
nums.sort()
|
|
||||||
length = len(nums)
|
|
||||||
div, mod = divmod(length, 2)
|
|
||||||
q1 = find_median(nums[:div])
|
|
||||||
half_length = sum((div, mod))
|
|
||||||
q3 = find_median(nums[half_length:length])
|
|
||||||
return q3 - q1
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
doctest.testmod()
|
|
@ -5,9 +5,9 @@ from collections.abc import Callable
|
|||||||
|
|
||||||
|
|
||||||
def line_length(
|
def line_length(
|
||||||
fnc: Callable[[float], float],
|
fnc: Callable[[int | float], int | float],
|
||||||
x_start: float,
|
x_start: int | float,
|
||||||
x_end: float,
|
x_end: int | float,
|
||||||
steps: int = 100,
|
steps: int = 100,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""
|
"""
|
||||||
|
@ -7,9 +7,9 @@ from collections.abc import Callable
|
|||||||
|
|
||||||
|
|
||||||
def trapezoidal_area(
|
def trapezoidal_area(
|
||||||
fnc: Callable[[float], float],
|
fnc: Callable[[int | float], int | float],
|
||||||
x_start: float,
|
x_start: int | float,
|
||||||
x_end: float,
|
x_end: int | float,
|
||||||
steps: int = 100,
|
steps: int = 100,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""
|
"""
|
||||||
|
@ -87,7 +87,7 @@ class Polynomial:
|
|||||||
|
|
||||||
return Polynomial(self.degree + polynomial_2.degree, coefficients)
|
return Polynomial(self.degree + polynomial_2.degree, coefficients)
|
||||||
|
|
||||||
def evaluate(self, substitution: float) -> float:
|
def evaluate(self, substitution: int | float) -> int | float:
|
||||||
"""
|
"""
|
||||||
Evaluates the polynomial at x.
|
Evaluates the polynomial at x.
|
||||||
>>> p = Polynomial(2, [1, 2, 3])
|
>>> p = Polynomial(2, [1, 2, 3])
|
||||||
@ -144,7 +144,7 @@ class Polynomial:
|
|||||||
coefficients[i] = self.coefficients[i + 1] * (i + 1)
|
coefficients[i] = self.coefficients[i + 1] * (i + 1)
|
||||||
return Polynomial(self.degree - 1, coefficients)
|
return Polynomial(self.degree - 1, coefficients)
|
||||||
|
|
||||||
def integral(self, constant: float = 0) -> Polynomial:
|
def integral(self, constant: int | float = 0) -> Polynomial:
|
||||||
"""
|
"""
|
||||||
Returns the integral of the polynomial.
|
Returns the integral of the polynomial.
|
||||||
>>> p = Polynomial(2, [1, 2, 3])
|
>>> p = Polynomial(2, [1, 2, 3])
|
||||||
|
@ -14,10 +14,10 @@ from __future__ import annotations
|
|||||||
|
|
||||||
|
|
||||||
def geometric_series(
|
def geometric_series(
|
||||||
nth_term: float,
|
nth_term: float | int,
|
||||||
start_term_a: float,
|
start_term_a: float | int,
|
||||||
common_ratio_r: float,
|
common_ratio_r: float | int,
|
||||||
) -> list[float]:
|
) -> list[float | int]:
|
||||||
"""
|
"""
|
||||||
Pure Python implementation of Geometric Series algorithm
|
Pure Python implementation of Geometric Series algorithm
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ def geometric_series(
|
|||||||
"""
|
"""
|
||||||
if not all((nth_term, start_term_a, common_ratio_r)):
|
if not all((nth_term, start_term_a, common_ratio_r)):
|
||||||
return []
|
return []
|
||||||
series: list[float] = []
|
series: list[float | int] = []
|
||||||
power = 1
|
power = 1
|
||||||
multiple = common_ratio_r
|
multiple = common_ratio_r
|
||||||
for _ in range(int(nth_term)):
|
for _ in range(int(nth_term)):
|
||||||
|
@ -13,7 +13,7 @@ python3 p_series.py
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
def p_series(nth_term: float | str, power: float | str) -> list[str]:
|
def p_series(nth_term: int | float | str, power: int | float | str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Pure Python implementation of P-Series algorithm
|
Pure Python implementation of P-Series algorithm
|
||||||
:return: The P-Series starting from 1 to last (nth) term
|
:return: The P-Series starting from 1 to last (nth) term
|
||||||
|
@ -8,7 +8,7 @@ from __future__ import annotations
|
|||||||
from math import pi, pow
|
from math import pi, pow
|
||||||
|
|
||||||
|
|
||||||
def vol_cube(side_length: float) -> float:
|
def vol_cube(side_length: int | float) -> float:
|
||||||
"""
|
"""
|
||||||
Calculate the Volume of a Cube.
|
Calculate the Volume of a Cube.
|
||||||
>>> vol_cube(1)
|
>>> vol_cube(1)
|
||||||
|
@ -141,7 +141,7 @@ class Matrix:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def order(self) -> tuple[int, int]:
|
def order(self) -> tuple[int, int]:
|
||||||
return self.num_rows, self.num_columns
|
return (self.num_rows, self.num_columns)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_square(self) -> bool:
|
def is_square(self) -> bool:
|
||||||
@ -315,7 +315,7 @@ class Matrix:
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
def __mul__(self, other: Matrix | float) -> Matrix:
|
def __mul__(self, other: Matrix | int | float) -> Matrix:
|
||||||
if isinstance(other, (int, float)):
|
if isinstance(other, (int, float)):
|
||||||
return Matrix(
|
return Matrix(
|
||||||
[[int(element * other) for element in row] for row in self.rows]
|
[[int(element * other) for element in row] for row in self.rows]
|
||||||
|
@ -47,7 +47,7 @@ def subtract(matrix_a: list[list[int]], matrix_b: list[list[int]]) -> list[list[
|
|||||||
raise TypeError("Expected a matrix, got int/list instead")
|
raise TypeError("Expected a matrix, got int/list instead")
|
||||||
|
|
||||||
|
|
||||||
def scalar_multiply(matrix: list[list[int]], n: float) -> list[list[float]]:
|
def scalar_multiply(matrix: list[list[int]], n: int | float) -> list[list[float]]:
|
||||||
"""
|
"""
|
||||||
>>> scalar_multiply([[1,2],[3,4]],5)
|
>>> scalar_multiply([[1,2],[3,4]],5)
|
||||||
[[5, 10], [15, 20]]
|
[[5, 10], [15, 20]]
|
||||||
@ -189,7 +189,9 @@ def main() -> None:
|
|||||||
matrix_c = [[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34], [41, 42, 43, 44]]
|
matrix_c = [[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34], [41, 42, 43, 44]]
|
||||||
matrix_d = [[3, 0, 2], [2, 0, -2], [0, 1, 1]]
|
matrix_d = [[3, 0, 2], [2, 0, -2], [0, 1, 1]]
|
||||||
print(f"Add Operation, {add(matrix_a, matrix_b) = } \n")
|
print(f"Add Operation, {add(matrix_a, matrix_b) = } \n")
|
||||||
print(f"Multiply Operation, {multiply(matrix_a, matrix_b) = } \n")
|
print(
|
||||||
|
f"Multiply Operation, {multiply(matrix_a, matrix_b) = } \n",
|
||||||
|
)
|
||||||
print(f"Identity: {identity(5)}\n")
|
print(f"Identity: {identity(5)}\n")
|
||||||
print(f"Minor of {matrix_c} = {minor(matrix_c, 1, 2)} \n")
|
print(f"Minor of {matrix_c} = {minor(matrix_c, 1, 2)} \n")
|
||||||
print(f"Determinant of {matrix_b} = {determinant(matrix_b)} \n")
|
print(f"Determinant of {matrix_b} = {determinant(matrix_b)} \n")
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
def search_in_a_sorted_matrix(mat: list[list[int]], m: int, n: int, key: float) -> None:
|
def search_in_a_sorted_matrix(
|
||||||
|
mat: list[list[int]], m: int, n: int, key: int | float
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
>>> search_in_a_sorted_matrix(
|
>>> search_in_a_sorted_matrix(
|
||||||
... [[2, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 5)
|
... [[2, 5, 7], [4, 8, 13], [9, 11, 15], [12, 17, 20]], 3, 3, 5)
|
||||||
|
@ -22,7 +22,7 @@ class Matrix:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
self.row, self.column = row, column
|
self.row, self.column = row, column
|
||||||
self.array = [[default_value for _ in range(column)] for _ in range(row)]
|
self.array = [[default_value for c in range(column)] for r in range(row)]
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
"""
|
"""
|
||||||
@ -54,15 +54,15 @@ class Matrix:
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
def validate_indices(self, loc: tuple[int, int]) -> bool:
|
def validate_indicies(self, loc: tuple[int, int]) -> bool:
|
||||||
"""
|
"""
|
||||||
<method Matrix.validate_indicies>
|
<method Matrix.validate_indicies>
|
||||||
Check if given indices are valid to pick element from matrix.
|
Check if given indices are valid to pick element from matrix.
|
||||||
Example:
|
Example:
|
||||||
>>> a = Matrix(2, 6, 0)
|
>>> a = Matrix(2, 6, 0)
|
||||||
>>> a.validate_indices((2, 7))
|
>>> a.validate_indicies((2, 7))
|
||||||
False
|
False
|
||||||
>>> a.validate_indices((0, 0))
|
>>> a.validate_indicies((0, 0))
|
||||||
True
|
True
|
||||||
"""
|
"""
|
||||||
if not (isinstance(loc, (list, tuple)) and len(loc) == 2):
|
if not (isinstance(loc, (list, tuple)) and len(loc) == 2):
|
||||||
@ -81,7 +81,7 @@ class Matrix:
|
|||||||
>>> a[1, 0]
|
>>> a[1, 0]
|
||||||
7
|
7
|
||||||
"""
|
"""
|
||||||
assert self.validate_indices(loc)
|
assert self.validate_indicies(loc)
|
||||||
return self.array[loc[0]][loc[1]]
|
return self.array[loc[0]][loc[1]]
|
||||||
|
|
||||||
def __setitem__(self, loc: tuple[int, int], value: float) -> None:
|
def __setitem__(self, loc: tuple[int, int], value: float) -> None:
|
||||||
@ -96,7 +96,7 @@ class Matrix:
|
|||||||
[ 1, 1, 1]
|
[ 1, 1, 1]
|
||||||
[ 1, 1, 51]
|
[ 1, 1, 51]
|
||||||
"""
|
"""
|
||||||
assert self.validate_indices(loc)
|
assert self.validate_indicies(loc)
|
||||||
self.array[loc[0]][loc[1]] = value
|
self.array[loc[0]][loc[1]] = value
|
||||||
|
|
||||||
def __add__(self, another: Matrix) -> Matrix:
|
def __add__(self, another: Matrix) -> Matrix:
|
||||||
@ -145,7 +145,7 @@ class Matrix:
|
|||||||
def __sub__(self, another: Matrix) -> Matrix:
|
def __sub__(self, another: Matrix) -> Matrix:
|
||||||
return self + (-another)
|
return self + (-another)
|
||||||
|
|
||||||
def __mul__(self, another: float | Matrix) -> Matrix:
|
def __mul__(self, another: int | float | Matrix) -> Matrix:
|
||||||
"""
|
"""
|
||||||
<method Matrix.__mul__>
|
<method Matrix.__mul__>
|
||||||
Return self * another.
|
Return self * another.
|
||||||
@ -233,7 +233,7 @@ class Matrix:
|
|||||||
v_t = v.transpose()
|
v_t = v.transpose()
|
||||||
numerator_factor = (v_t * self * u)[0, 0] + 1
|
numerator_factor = (v_t * self * u)[0, 0] + 1
|
||||||
if numerator_factor == 0:
|
if numerator_factor == 0:
|
||||||
return None # It's not invertible
|
return None # It's not invertable
|
||||||
return self - ((self * u) * (v_t * self) * (1.0 / numerator_factor))
|
return self - ((self * u) * (v_t * self) * (1.0 / numerator_factor))
|
||||||
|
|
||||||
|
|
||||||
|
@ -263,7 +263,9 @@ def _maybe_download(filename, work_directory, source_url):
|
|||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
|
|
||||||
@deprecated(None, "Please use alternatives such as: tensorflow_datasets.load('mnist')")
|
@deprecated(
|
||||||
|
None, "Please use alternatives such as:" " tensorflow_datasets.load('mnist')"
|
||||||
|
)
|
||||||
def read_data_sets(
|
def read_data_sets(
|
||||||
train_dir,
|
train_dir,
|
||||||
fake_data=False,
|
fake_data=False,
|
@ -1,52 +0,0 @@
|
|||||||
"""
|
|
||||||
Title : Calculate altitude using Pressure
|
|
||||||
|
|
||||||
Description :
|
|
||||||
The below algorithm approximates the altitude using Barometric formula
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_altitude_at_pressure(pressure: float) -> float:
|
|
||||||
"""
|
|
||||||
This method calculates the altitude from Pressure wrt to
|
|
||||||
Sea level pressure as reference .Pressure is in Pascals
|
|
||||||
https://en.wikipedia.org/wiki/Pressure_altitude
|
|
||||||
https://community.bosch-sensortec.com/t5/Question-and-answers/How-to-calculate-the-altitude-from-the-pressure-sensor-data/qaq-p/5702
|
|
||||||
|
|
||||||
H = 44330 * [1 - (P/p0)^(1/5.255) ]
|
|
||||||
|
|
||||||
Where :
|
|
||||||
H = altitude (m)
|
|
||||||
P = measured pressure
|
|
||||||
p0 = reference pressure at sea level 101325 Pa
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
>>> get_altitude_at_pressure(pressure=100_000)
|
|
||||||
105.47836610778828
|
|
||||||
>>> get_altitude_at_pressure(pressure=101_325)
|
|
||||||
0.0
|
|
||||||
>>> get_altitude_at_pressure(pressure=80_000)
|
|
||||||
1855.873388064995
|
|
||||||
>>> get_altitude_at_pressure(pressure=201_325)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Value Higher than Pressure at Sea Level !
|
|
||||||
>>> get_altitude_at_pressure(pressure=-80_000)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Atmospheric Pressure can not be negative !
|
|
||||||
"""
|
|
||||||
|
|
||||||
if pressure > 101325:
|
|
||||||
raise ValueError("Value Higher than Pressure at Sea Level !")
|
|
||||||
if pressure < 0:
|
|
||||||
raise ValueError("Atmospheric Pressure can not be negative !")
|
|
||||||
return 44_330 * (1 - (pressure / 101_325) ** (1 / 5.5255))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
doctest.testmod()
|
|
@ -1,178 +0,0 @@
|
|||||||
from math import pow, sqrt
|
|
||||||
|
|
||||||
from scipy.constants import G, c, pi
|
|
||||||
|
|
||||||
"""
|
|
||||||
These two functions will return the radii of impact for a target object
|
|
||||||
of mass M and radius R as well as it's effective cross sectional area σ(sigma).
|
|
||||||
That is to say any projectile with velocity v passing within σ, will impact the
|
|
||||||
target object with mass M. The derivation of which is given at the bottom
|
|
||||||
of this file.
|
|
||||||
|
|
||||||
The derivation shows that a projectile does not need to aim directly at the target
|
|
||||||
body in order to hit it, as R_capture>R_target. Astronomers refer to the effective
|
|
||||||
cross section for capture as σ=π*R_capture**2.
|
|
||||||
|
|
||||||
This algorithm does not account for an N-body problem.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def capture_radii(
|
|
||||||
target_body_radius: float, target_body_mass: float, projectile_velocity: float
|
|
||||||
) -> float:
|
|
||||||
"""
|
|
||||||
Input Params:
|
|
||||||
-------------
|
|
||||||
target_body_radius: Radius of the central body SI units: meters | m
|
|
||||||
target_body_mass: Mass of the central body SI units: kilograms | kg
|
|
||||||
projectile_velocity: Velocity of object moving toward central body
|
|
||||||
SI units: meters/second | m/s
|
|
||||||
Returns:
|
|
||||||
--------
|
|
||||||
>>> capture_radii(6.957e8, 1.99e30, 25000.0)
|
|
||||||
17209590691.0
|
|
||||||
>>> capture_radii(-6.957e8, 1.99e30, 25000.0)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Radius cannot be less than 0
|
|
||||||
>>> capture_radii(6.957e8, -1.99e30, 25000.0)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Mass cannot be less than 0
|
|
||||||
>>> capture_radii(6.957e8, 1.99e30, c+1)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Cannot go beyond speed of light
|
|
||||||
|
|
||||||
Returned SI units:
|
|
||||||
------------------
|
|
||||||
meters | m
|
|
||||||
"""
|
|
||||||
|
|
||||||
if target_body_mass < 0:
|
|
||||||
raise ValueError("Mass cannot be less than 0")
|
|
||||||
if target_body_radius < 0:
|
|
||||||
raise ValueError("Radius cannot be less than 0")
|
|
||||||
if projectile_velocity > c:
|
|
||||||
raise ValueError("Cannot go beyond speed of light")
|
|
||||||
|
|
||||||
escape_velocity_squared = (2 * G * target_body_mass) / target_body_radius
|
|
||||||
capture_radius = target_body_radius * sqrt(
|
|
||||||
1 + escape_velocity_squared / pow(projectile_velocity, 2)
|
|
||||||
)
|
|
||||||
return round(capture_radius, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def capture_area(capture_radius: float) -> float:
|
|
||||||
"""
|
|
||||||
Input Param:
|
|
||||||
------------
|
|
||||||
capture_radius: The radius of orbital capture and impact for a central body of
|
|
||||||
mass M and a projectile moving towards it with velocity v
|
|
||||||
SI units: meters | m
|
|
||||||
Returns:
|
|
||||||
--------
|
|
||||||
>>> capture_area(17209590691)
|
|
||||||
9.304455331329126e+20
|
|
||||||
>>> capture_area(-1)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Cannot have a capture radius less than 0
|
|
||||||
|
|
||||||
Returned SI units:
|
|
||||||
------------------
|
|
||||||
meters*meters | m**2
|
|
||||||
"""
|
|
||||||
|
|
||||||
if capture_radius < 0:
|
|
||||||
raise ValueError("Cannot have a capture radius less than 0")
|
|
||||||
sigma = pi * pow(capture_radius, 2)
|
|
||||||
return round(sigma, 0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
from doctest import testmod
|
|
||||||
|
|
||||||
testmod()
|
|
||||||
|
|
||||||
"""
|
|
||||||
Derivation:
|
|
||||||
|
|
||||||
Let: Mt=target mass, Rt=target radius, v=projectile_velocity,
|
|
||||||
r_0=radius of projectile at instant 0 to CM of target
|
|
||||||
v_p=v at closest approach,
|
|
||||||
r_p=radius from projectile to target CM at closest approach,
|
|
||||||
R_capture= radius of impact for projectile with velocity v
|
|
||||||
|
|
||||||
(1)At time=0 the projectile's energy falling from infinity| E=K+U=0.5*m*(v**2)+0
|
|
||||||
|
|
||||||
E_initial=0.5*m*(v**2)
|
|
||||||
|
|
||||||
(2)at time=0 the angular momentum of the projectile relative to CM target|
|
|
||||||
L_initial=m*r_0*v*sin(Θ)->m*r_0*v*(R_capture/r_0)->m*v*R_capture
|
|
||||||
|
|
||||||
L_i=m*v*R_capture
|
|
||||||
|
|
||||||
(3)The energy of the projectile at closest approach will be its kinetic energy
|
|
||||||
at closest approach plus gravitational potential energy(-(GMm)/R)|
|
|
||||||
E_p=K_p+U_p->E_p=0.5*m*(v_p**2)-(G*Mt*m)/r_p
|
|
||||||
|
|
||||||
E_p=0.0.5*m*(v_p**2)-(G*Mt*m)/r_p
|
|
||||||
|
|
||||||
(4)The angular momentum of the projectile relative to the target at closest
|
|
||||||
approach will be L_p=m*r_p*v_p*sin(Θ), however relative to the target Θ=90°
|
|
||||||
sin(90°)=1|
|
|
||||||
|
|
||||||
L_p=m*r_p*v_p
|
|
||||||
(5)Using conservation of angular momentum and energy, we can write a quadratic
|
|
||||||
equation that solves for r_p|
|
|
||||||
|
|
||||||
(a)
|
|
||||||
Ei=Ep-> 0.5*m*(v**2)=0.5*m*(v_p**2)-(G*Mt*m)/r_p-> v**2=v_p**2-(2*G*Mt)/r_p
|
|
||||||
|
|
||||||
(b)
|
|
||||||
Li=Lp-> m*v*R_capture=m*r_p*v_p-> v*R_capture=r_p*v_p-> v_p=(v*R_capture)/r_p
|
|
||||||
|
|
||||||
(c) b plugs int a|
|
|
||||||
v**2=((v*R_capture)/r_p)**2-(2*G*Mt)/r_p->
|
|
||||||
|
|
||||||
v**2-(v**2)*(R_c**2)/(r_p**2)+(2*G*Mt)/r_p=0->
|
|
||||||
|
|
||||||
(v**2)*(r_p**2)+2*G*Mt*r_p-(v**2)*(R_c**2)=0
|
|
||||||
|
|
||||||
(d) Using the quadratic formula, we'll solve for r_p then rearrange to solve to
|
|
||||||
R_capture
|
|
||||||
|
|
||||||
r_p=(-2*G*Mt ± sqrt(4*G^2*Mt^2+ 4(v^4*R_c^2)))/(2*v^2)->
|
|
||||||
|
|
||||||
r_p=(-G*Mt ± sqrt(G^2*Mt+v^4*R_c^2))/v^2->
|
|
||||||
|
|
||||||
r_p<0 is something we can ignore, as it has no physical meaning for our purposes.->
|
|
||||||
|
|
||||||
r_p=(-G*Mt)/v^2 + sqrt(G^2*Mt^2/v^4 + R_c^2)
|
|
||||||
|
|
||||||
(e)We are trying to solve for R_c. We are looking for impact, so we want r_p=Rt
|
|
||||||
|
|
||||||
Rt + G*Mt/v^2 = sqrt(G^2*Mt^2/v^4 + R_c^2)->
|
|
||||||
|
|
||||||
(Rt + G*Mt/v^2)^2 = G^2*Mt^2/v^4 + R_c^2->
|
|
||||||
|
|
||||||
Rt^2 + 2*G*Mt*Rt/v^2 + G^2*Mt^2/v^4 = G^2*Mt^2/v^4 + R_c^2->
|
|
||||||
|
|
||||||
Rt**2 + 2*G*Mt*Rt/v**2 = R_c**2->
|
|
||||||
|
|
||||||
Rt**2 * (1 + 2*G*Mt/Rt *1/v**2) = R_c**2->
|
|
||||||
|
|
||||||
escape velocity = sqrt(2GM/R)= v_escape**2=2GM/R->
|
|
||||||
|
|
||||||
Rt**2 * (1 + v_esc**2/v**2) = R_c**2->
|
|
||||||
|
|
||||||
(6)
|
|
||||||
R_capture = Rt * sqrt(1 + v_esc**2/v**2)
|
|
||||||
|
|
||||||
Source: Problem Set 3 #8 c.Fall_2017|Honors Astronomy|Professor Rachel Bezanson
|
|
||||||
|
|
||||||
Source #2: http://www.nssc.ac.cn/wxzygx/weixin/201607/P020160718380095698873.pdf
|
|
||||||
8.8 Planetary Rendezvous: Pg.368
|
|
||||||
"""
|
|
@ -53,40 +53,6 @@ def volume_of_gas_system(moles: float, kelvin: float, pressure: float) -> float:
|
|||||||
return moles * kelvin * UNIVERSAL_GAS_CONSTANT / pressure
|
return moles * kelvin * UNIVERSAL_GAS_CONSTANT / pressure
|
||||||
|
|
||||||
|
|
||||||
def temperature_of_gas_system(moles: float, volume: float, pressure: float) -> float:
|
|
||||||
"""
|
|
||||||
>>> temperature_of_gas_system(2, 100, 5)
|
|
||||||
30.068090996146232
|
|
||||||
>>> temperature_of_gas_system(11, 5009, 1000)
|
|
||||||
54767.66101807144
|
|
||||||
>>> temperature_of_gas_system(3, -0.46, 23.5)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Invalid inputs. Enter positive value.
|
|
||||||
"""
|
|
||||||
if moles < 0 or volume < 0 or pressure < 0:
|
|
||||||
raise ValueError("Invalid inputs. Enter positive value.")
|
|
||||||
|
|
||||||
return pressure * volume / (moles * UNIVERSAL_GAS_CONSTANT)
|
|
||||||
|
|
||||||
|
|
||||||
def moles_of_gas_system(kelvin: float, volume: float, pressure: float) -> float:
|
|
||||||
"""
|
|
||||||
>>> moles_of_gas_system(100, 5, 10)
|
|
||||||
0.06013618199229246
|
|
||||||
>>> moles_of_gas_system(110, 5009, 1000)
|
|
||||||
5476.766101807144
|
|
||||||
>>> moles_of_gas_system(3, -0.46, 23.5)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
ValueError: Invalid inputs. Enter positive value.
|
|
||||||
"""
|
|
||||||
if kelvin < 0 or volume < 0 or pressure < 0:
|
|
||||||
raise ValueError("Invalid inputs. Enter positive value.")
|
|
||||||
|
|
||||||
return pressure * volume / (kelvin * UNIVERSAL_GAS_CONSTANT)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from doctest import testmod
|
from doctest import testmod
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ def newtons_second_law_of_motion(mass: float, acceleration: float) -> float:
|
|||||||
>>> newtons_second_law_of_motion(2.0, 1)
|
>>> newtons_second_law_of_motion(2.0, 1)
|
||||||
2.0
|
2.0
|
||||||
"""
|
"""
|
||||||
force = 0.0
|
force = float()
|
||||||
try:
|
try:
|
||||||
force = mass * acceleration
|
force = mass * acceleration
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -49,7 +49,6 @@ select = [ # https://beta.ruff.rs/docs/rules
|
|||||||
"ICN", # flake8-import-conventions
|
"ICN", # flake8-import-conventions
|
||||||
"INP", # flake8-no-pep420
|
"INP", # flake8-no-pep420
|
||||||
"INT", # flake8-gettext
|
"INT", # flake8-gettext
|
||||||
"ISC", # flake8-implicit-str-concat
|
|
||||||
"N", # pep8-naming
|
"N", # pep8-naming
|
||||||
"NPY", # NumPy-specific rules
|
"NPY", # NumPy-specific rules
|
||||||
"PGH", # pygrep-hooks
|
"PGH", # pygrep-hooks
|
||||||
@ -73,6 +72,7 @@ select = [ # https://beta.ruff.rs/docs/rules
|
|||||||
# "DJ", # flake8-django
|
# "DJ", # flake8-django
|
||||||
# "ERA", # eradicate -- DO NOT FIX
|
# "ERA", # eradicate -- DO NOT FIX
|
||||||
# "FBT", # flake8-boolean-trap # FIX ME
|
# "FBT", # flake8-boolean-trap # FIX ME
|
||||||
|
# "ISC", # flake8-implicit-str-concat # FIX ME
|
||||||
# "PD", # pandas-vet
|
# "PD", # pandas-vet
|
||||||
# "PT", # flake8-pytest-style
|
# "PT", # flake8-pytest-style
|
||||||
# "PTH", # flake8-use-pathlib # FIX ME
|
# "PTH", # flake8-use-pathlib # FIX ME
|
||||||
|
@ -9,7 +9,6 @@ pandas
|
|||||||
pillow
|
pillow
|
||||||
projectq
|
projectq
|
||||||
qiskit
|
qiskit
|
||||||
qiskit-aer
|
|
||||||
requests
|
requests
|
||||||
rich
|
rich
|
||||||
scikit-fuzzy
|
scikit-fuzzy
|
||||||
|
@ -4,28 +4,14 @@ This algorithm iterates through a sorted collection with a step of n^(1/2),
|
|||||||
until the element compared is bigger than the one searched.
|
until the element compared is bigger than the one searched.
|
||||||
It will then perform a linear search until it matches the wanted number.
|
It will then perform a linear search until it matches the wanted number.
|
||||||
If not found, it returns -1.
|
If not found, it returns -1.
|
||||||
|
|
||||||
https://en.wikipedia.org/wiki/Jump_search
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import math
|
import math
|
||||||
from collections.abc import Sequence
|
|
||||||
from typing import Any, Protocol, TypeVar
|
|
||||||
|
|
||||||
|
|
||||||
class Comparable(Protocol):
|
def jump_search(arr: list, x: int) -> int:
|
||||||
def __lt__(self, other: Any, /) -> bool:
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar("T", bound=Comparable)
|
|
||||||
|
|
||||||
|
|
||||||
def jump_search(arr: Sequence[T], item: T) -> int:
|
|
||||||
"""
|
"""
|
||||||
Python implementation of the jump search algorithm.
|
Pure Python implementation of the jump search algorithm.
|
||||||
Return the index if the `item` is found, otherwise return -1.
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> jump_search([0, 1, 2, 3, 4, 5], 3)
|
>>> jump_search([0, 1, 2, 3, 4, 5], 3)
|
||||||
3
|
3
|
||||||
@ -35,36 +21,31 @@ def jump_search(arr: Sequence[T], item: T) -> int:
|
|||||||
-1
|
-1
|
||||||
>>> jump_search([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610], 55)
|
>>> jump_search([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610], 55)
|
||||||
10
|
10
|
||||||
>>> jump_search(["aa", "bb", "cc", "dd", "ee", "ff"], "ee")
|
|
||||||
4
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
arr_size = len(arr)
|
n = len(arr)
|
||||||
block_size = int(math.sqrt(arr_size))
|
step = int(math.floor(math.sqrt(n)))
|
||||||
|
|
||||||
prev = 0
|
prev = 0
|
||||||
step = block_size
|
while arr[min(step, n) - 1] < x:
|
||||||
while arr[min(step, arr_size) - 1] < item:
|
|
||||||
prev = step
|
prev = step
|
||||||
step += block_size
|
step += int(math.floor(math.sqrt(n)))
|
||||||
if prev >= arr_size:
|
if prev >= n:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
while arr[prev] < item:
|
while arr[prev] < x:
|
||||||
prev += 1
|
prev = prev + 1
|
||||||
if prev == min(step, arr_size):
|
if prev == min(step, n):
|
||||||
return -1
|
return -1
|
||||||
if arr[prev] == item:
|
if arr[prev] == x:
|
||||||
return prev
|
return prev
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
user_input = input("Enter numbers separated by a comma:\n").strip()
|
user_input = input("Enter numbers separated by a comma:\n").strip()
|
||||||
array = [int(item) for item in user_input.split(",")]
|
arr = [int(item) for item in user_input.split(",")]
|
||||||
x = int(input("Enter the number to be searched:\n"))
|
x = int(input("Enter the number to be searched:\n"))
|
||||||
|
res = jump_search(arr, x)
|
||||||
res = jump_search(array, x)
|
|
||||||
if res == -1:
|
if res == -1:
|
||||||
print("Number not found!")
|
print("Number not found!")
|
||||||
else:
|
else:
|
||||||
|
@ -15,7 +15,7 @@ def linear_search(sequence: list, target: int) -> int:
|
|||||||
:param sequence: a collection with comparable items (as sorted items not required
|
:param sequence: a collection with comparable items (as sorted items not required
|
||||||
in Linear Search)
|
in Linear Search)
|
||||||
:param target: item value to search
|
:param target: item value to search
|
||||||
:return: index of found item or -1 if item is not found
|
:return: index of found item or None if item is not found
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> linear_search([0, 5, 7, 10, 15], 0)
|
>>> linear_search([0, 5, 7, 10, 15], 0)
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
from typing import Any
|
def bubble_sort(collection):
|
||||||
|
|
||||||
|
|
||||||
def bubble_sort(collection: list[Any]) -> list[Any]:
|
|
||||||
"""Pure implementation of bubble sort algorithm in Python
|
"""Pure implementation of bubble sort algorithm in Python
|
||||||
|
|
||||||
:param collection: some mutable ordered collection with heterogeneous
|
:param collection: some mutable ordered collection with heterogeneous
|
||||||
@ -31,9 +28,9 @@ def bubble_sort(collection: list[Any]) -> list[Any]:
|
|||||||
True
|
True
|
||||||
"""
|
"""
|
||||||
length = len(collection)
|
length = len(collection)
|
||||||
for i in reversed(range(length)):
|
for i in range(length - 1):
|
||||||
swapped = False
|
swapped = False
|
||||||
for j in range(i):
|
for j in range(length - 1 - i):
|
||||||
if collection[j] > collection[j + 1]:
|
if collection[j] > collection[j + 1]:
|
||||||
swapped = True
|
swapped = True
|
||||||
collection[j], collection[j + 1] = collection[j + 1], collection[j]
|
collection[j], collection[j + 1] = collection[j + 1], collection[j]
|
||||||
|
@ -22,7 +22,9 @@ def is_sri_lankan_phone_number(phone: str) -> bool:
|
|||||||
False
|
False
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pattern = re.compile(r"^(?:0|94|\+94|0{2}94)7(0|1|2|4|5|6|7|8)(-| |)\d{7}$")
|
pattern = re.compile(
|
||||||
|
r"^(?:0|94|\+94|0{2}94)" r"7(0|1|2|4|5|6|7|8)" r"(-| |)" r"\d{7}$"
|
||||||
|
)
|
||||||
|
|
||||||
return bool(re.search(pattern, phone))
|
return bool(re.search(pattern, phone))
|
||||||
|
|
||||||
|
@ -1,117 +0,0 @@
|
|||||||
"""
|
|
||||||
Implements an is valid email address algorithm
|
|
||||||
|
|
||||||
@ https://en.wikipedia.org/wiki/Email_address
|
|
||||||
"""
|
|
||||||
|
|
||||||
import string
|
|
||||||
|
|
||||||
email_tests: tuple[tuple[str, bool], ...] = (
|
|
||||||
("simple@example.com", True),
|
|
||||||
("very.common@example.com", True),
|
|
||||||
("disposable.style.email.with+symbol@example.com", True),
|
|
||||||
("other-email-with-hyphen@and.subdomains.example.com", True),
|
|
||||||
("fully-qualified-domain@example.com", True),
|
|
||||||
("user.name+tag+sorting@example.com", True),
|
|
||||||
("x@example.com", True),
|
|
||||||
("example-indeed@strange-example.com", True),
|
|
||||||
("test/test@test.com", True),
|
|
||||||
(
|
|
||||||
"123456789012345678901234567890123456789012345678901234567890123@example.com",
|
|
||||||
True,
|
|
||||||
),
|
|
||||||
("admin@mailserver1", True),
|
|
||||||
("example@s.example", True),
|
|
||||||
("Abc.example.com", False),
|
|
||||||
("A@b@c@example.com", False),
|
|
||||||
("abc@example..com", False),
|
|
||||||
("a(c)d,e:f;g<h>i[j\\k]l@example.com", False),
|
|
||||||
(
|
|
||||||
"12345678901234567890123456789012345678901234567890123456789012345@example.com",
|
|
||||||
False,
|
|
||||||
),
|
|
||||||
("i.like.underscores@but_its_not_allowed_in_this_part", False),
|
|
||||||
("", False),
|
|
||||||
)
|
|
||||||
|
|
||||||
# The maximum octets (one character as a standard unicode character is one byte)
|
|
||||||
# that the local part and the domain part can have
|
|
||||||
MAX_LOCAL_PART_OCTETS = 64
|
|
||||||
MAX_DOMAIN_OCTETS = 255
|
|
||||||
|
|
||||||
|
|
||||||
def is_valid_email_address(email: str) -> bool:
|
|
||||||
"""
|
|
||||||
Returns True if the passed email address is valid.
|
|
||||||
|
|
||||||
The local part of the email precedes the singular @ symbol and
|
|
||||||
is associated with a display-name. For example, "john.smith"
|
|
||||||
The domain is stricter than the local part and follows the @ symbol.
|
|
||||||
|
|
||||||
Global email checks:
|
|
||||||
1. There can only be one @ symbol in the email address. Technically if the
|
|
||||||
@ symbol is quoted in the local-part, then it is valid, however this
|
|
||||||
implementation ignores "" for now.
|
|
||||||
(See https://en.wikipedia.org/wiki/Email_address#:~:text=If%20quoted,)
|
|
||||||
2. The local-part and the domain are limited to a certain number of octets. With
|
|
||||||
unicode storing a single character in one byte, each octet is equivalent to
|
|
||||||
a character. Hence, we can just check the length of the string.
|
|
||||||
Checks for the local-part:
|
|
||||||
3. The local-part may contain: upper and lowercase latin letters, digits 0 to 9,
|
|
||||||
and printable characters (!#$%&'*+-/=?^_`{|}~)
|
|
||||||
4. The local-part may also contain a "." in any place that is not the first or
|
|
||||||
last character, and may not have more than one "." consecutively.
|
|
||||||
|
|
||||||
Checks for the domain:
|
|
||||||
5. The domain may contain: upper and lowercase latin letters and digits 0 to 9
|
|
||||||
6. Hyphen "-", provided that it is not the first or last character
|
|
||||||
7. The domain may also contain a "." in any place that is not the first or
|
|
||||||
last character, and may not have more than one "." consecutively.
|
|
||||||
|
|
||||||
>>> for email, valid in email_tests:
|
|
||||||
... assert is_valid_email_address(email) == valid
|
|
||||||
"""
|
|
||||||
|
|
||||||
# (1.) Make sure that there is only one @ symbol in the email address
|
|
||||||
if email.count("@") != 1:
|
|
||||||
return False
|
|
||||||
|
|
||||||
local_part, domain = email.split("@")
|
|
||||||
# (2.) Check octet length of the local part and domain
|
|
||||||
if len(local_part) > MAX_LOCAL_PART_OCTETS or len(domain) > MAX_DOMAIN_OCTETS:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# (3.) Validate the characters in the local-part
|
|
||||||
if any(
|
|
||||||
char not in string.ascii_letters + string.digits + ".(!#$%&'*+-/=?^_`{|}~)"
|
|
||||||
for char in local_part
|
|
||||||
):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# (4.) Validate the placement of "." characters in the local-part
|
|
||||||
if local_part.startswith(".") or local_part.endswith(".") or ".." in local_part:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# (5.) Validate the characters in the domain
|
|
||||||
if any(char not in string.ascii_letters + string.digits + ".-" for char in domain):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# (6.) Validate the placement of "-" characters
|
|
||||||
if domain.startswith("-") or domain.endswith("."):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# (7.) Validate the placement of "." characters
|
|
||||||
if domain.startswith(".") or domain.endswith(".") or ".." in domain:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import doctest
|
|
||||||
|
|
||||||
doctest.testmod()
|
|
||||||
|
|
||||||
for email, valid in email_tests:
|
|
||||||
is_valid = is_valid_email_address(email)
|
|
||||||
assert is_valid == valid, f"{email} is {is_valid}"
|
|
||||||
print(f"Email address {email} is {'not ' if not is_valid else ''}valid")
|
|
@ -4,21 +4,17 @@ This is to show simple COVID19 info fetching from worldometers site using lxml
|
|||||||
more convenient to use in Python web projects (e.g. Django or Flask-based)
|
more convenient to use in Python web projects (e.g. Django or Flask-based)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import NamedTuple
|
from collections import namedtuple
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from lxml import html # type: ignore
|
from lxml import html # type: ignore
|
||||||
|
|
||||||
|
covid_data = namedtuple("covid_data", "cases deaths recovered")
|
||||||
class CovidData(NamedTuple):
|
|
||||||
cases: int
|
|
||||||
deaths: int
|
|
||||||
recovered: int
|
|
||||||
|
|
||||||
|
|
||||||
def covid_stats(url: str = "https://www.worldometers.info/coronavirus/") -> CovidData:
|
def covid_stats(url: str = "https://www.worldometers.info/coronavirus/") -> covid_data:
|
||||||
xpath_str = '//div[@class = "maincounter-number"]/span/text()'
|
xpath_str = '//div[@class = "maincounter-number"]/span/text()'
|
||||||
return CovidData(*html.fromstring(requests.get(url).content).xpath(xpath_str))
|
return covid_data(*html.fromstring(requests.get(url).content).xpath(xpath_str))
|
||||||
|
|
||||||
|
|
||||||
fmt = """Total COVID-19 cases in the world: {}
|
fmt = """Total COVID-19 cases in the world: {}
|
||||||
|
@ -3,18 +3,12 @@ from bs4 import BeautifulSoup
|
|||||||
|
|
||||||
|
|
||||||
def stock_price(symbol: str = "AAPL") -> str:
|
def stock_price(symbol: str = "AAPL") -> str:
|
||||||
url = f"https://finance.yahoo.com/quote/{symbol}?p={symbol}"
|
url = f"https://in.finance.yahoo.com/quote/{symbol}?s={symbol}"
|
||||||
yahoo_finance_source = requests.get(url, headers={"USER-AGENT": "Mozilla/5.0"}).text
|
soup = BeautifulSoup(requests.get(url).text, "html.parser")
|
||||||
soup = BeautifulSoup(yahoo_finance_source, "html.parser")
|
class_ = "My(6px) Pos(r) smartphone_Mt(6px)"
|
||||||
specific_fin_streamer_tag = soup.find("fin-streamer", {"data-test": "qsp-price"})
|
return soup.find("div", class_=class_).find("span").text
|
||||||
|
|
||||||
if specific_fin_streamer_tag:
|
|
||||||
text = specific_fin_streamer_tag.get_text()
|
|
||||||
return text
|
|
||||||
return "No <fin-streamer> tag with the specified data-test attribute found."
|
|
||||||
|
|
||||||
|
|
||||||
# Search for the symbol at https://finance.yahoo.com/lookup
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
for symbol in "AAPL AMZN IBM GOOG MSFT ORCL".split():
|
for symbol in "AAPL AMZN IBM GOOG MSFT ORCL".split():
|
||||||
print(f"Current {symbol:<4} stock price is {stock_price(symbol):>8}")
|
print(f"Current {symbol:<4} stock price is {stock_price(symbol):>8}")
|
||||||
|
@ -22,5 +22,6 @@ def world_covid19_stats(url: str = "https://www.worldometers.info/coronavirus")
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("\033[1m COVID-19 Status of the World \033[0m\n")
|
print("\033[1m" + "COVID-19 Status of the World" + "\033[0m\n")
|
||||||
print("\n".join(f"{key}\n{value}" for key, value in world_covid19_stats().items()))
|
for key, value in world_covid19_stats().items():
|
||||||
|
print(f"{key}\n{value}\n")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user