Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c7d9135
Create multibit_manipulation.py
billbreit May 28, 2024
bb46e1a
Fix errrors in multibit_manipulation
billbreit May 28, 2024
305f444
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 28, 2024
b501f22
Fix Ruff formatting
billbreit May 29, 2024
3d1342e
Merge branch 'master' of https://github.com/billbreit/Python
billbreit May 29, 2024
01be044
Struggling
billbreit May 29, 2024
23956f5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 29, 2024
c32638f
Recommit
billbreit May 29, 2024
a471d00
Merge branch 'master' of https://github.com/billbreit/Python
billbreit May 29, 2024
93610d9
Fix type hints, validation errors
billbreit May 29, 2024
0ef3e6b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 29, 2024
29b6e8f
Fix tabs instead of spaces in comments
billbreit May 29, 2024
c9d6a61
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 29, 2024
9002513
Fix type hint for returns
billbreit May 29, 2024
27aebea
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 29, 2024
82695f8
Clean up return types
billbreit May 30, 2024
6e81a51
Cleanup comments
billbreit May 31, 2024
5a6275b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 31, 2024
cb65485
Fix Ruff error
billbreit May 31, 2024
1b582d2
Merge branch 'master' of https://github.com/billbreit/Python
billbreit May 31, 2024
db14663
Fix details
billbreit Jun 1, 2024
13f6fdb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 1, 2024
c05cc65
Strings too long
billbreit Jun 1, 2024
b7d8d7f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 1, 2024
d8654c2
Keep trying
billbreit Jun 1, 2024
50dfbce
Spelling
billbreit Jun 1, 2024
0c7386e
Merge branch 'master' into master
cclauss Sep 15, 2026
495dc9e
updating DIRECTORY.md
cclauss Sep 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
* [Generate Parentheses Iterative](backtracking/generate_parentheses_iterative.py)
* [Hamiltonian Cycle](backtracking/hamiltonian_cycle.py)
* [Knight Tour](backtracking/knight_tour.py)
* [M Coloring Problem](backtracking/m_coloring_problem.py)
* [Match Word Pattern](backtracking/match_word_pattern.py)
* [Minimax](backtracking/minimax.py)
* [N Queens](backtracking/n_queens.py)
Expand Down Expand Up @@ -97,6 +98,7 @@
* [Is Power Of Two](bit_manipulation/is_power_of_two.py)
* [Largest Pow Of Two Le Num](bit_manipulation/largest_pow_of_two_le_num.py)
* [Missing Number](bit_manipulation/missing_number.py)
* [Multibit Manipulation](bit_manipulation/multibit_manipulation.py)
* [Next Power Of Two](bit_manipulation/next_power_of_two.py)
* [Numbers Different Signs](bit_manipulation/numbers_different_signs.py)
* [Parity](bit_manipulation/parity.py)
Expand All @@ -108,6 +110,9 @@

## [Blockchain](blockchain)
* [Diophantine Equation](blockchain/diophantine_equation.py)
* [Merkle Tree](blockchain/merkle_tree.py)
* [Simple Blockchain](blockchain/simple_blockchain.py)
* [Simple Proof Of Work](blockchain/simple_proof_of_work.py)

## [Boolean Algebra](boolean_algebra)
* [And Gate](boolean_algebra/and_gate.py)
Expand Down Expand Up @@ -166,6 +171,7 @@
* [Porta Cipher](ciphers/porta_cipher.py)
* [Rabin Miller](ciphers/rabin_miller.py)
* [Rail Fence Cipher](ciphers/rail_fence_cipher.py)
* [Rc4](ciphers/rc4.py)
* [Rot13](ciphers/rot13.py)
* [Rsa Cipher](ciphers/rsa_cipher.py)
* [Rsa Factorization](ciphers/rsa_factorization.py)
Expand All @@ -180,6 +186,7 @@
* [Vernam Cipher](ciphers/vernam_cipher.py)
* [Vigenere Cipher](ciphers/vigenere_cipher.py)
* [Xor Cipher](ciphers/xor_cipher.py)
* [Xtea](ciphers/xtea.py)

## [Computer Vision](computer_vision)
* [Cnn Classification](computer_vision/cnn_classification.py)
Expand All @@ -198,13 +205,17 @@
## [Conversions](conversions)
* [Astronomical Length Scale Conversion](conversions/astronomical_length_scale_conversion.py)
* [Binary To Decimal](conversions/binary_to_decimal.py)
* [Binary To Excess3](conversions/binary_to_excess3.py)
* [Binary To Gray](conversions/binary_to_gray.py)
* [Binary To Gray Code](conversions/binary_to_gray_code.py)
* [Binary To Hexadecimal](conversions/binary_to_hexadecimal.py)
* [Binary To Octal](conversions/binary_to_octal.py)
* [Convert Number To Words](conversions/convert_number_to_words.py)
* [Decimal To Any](conversions/decimal_to_any.py)
* [Decimal To Binary](conversions/decimal_to_binary.py)
* [Decimal To Hexadecimal](conversions/decimal_to_hexadecimal.py)
* [Decimal To Octal](conversions/decimal_to_octal.py)
* [Endianness](conversions/endianness.py)
* [Energy Conversions](conversions/energy_conversions.py)
* [Excel Title To Column](conversions/excel_title_to_column.py)
* [Hex To Bin](conversions/hex_to_bin.py)
Expand Down Expand Up @@ -689,6 +700,7 @@
* [Astar](machine_learning/astar.py)
* [Automatic Differentiation](machine_learning/automatic_differentiation.py)
* [Data Transformations](machine_learning/data_transformations.py)
* [Dbscan](machine_learning/dbscan.py)
* [Decision Tree](machine_learning/decision_tree.py)
* [Dimensionality Reduction](machine_learning/dimensionality_reduction.py)
* [Federated Averaging](machine_learning/federated_averaging.py)
Expand All @@ -712,15 +724,18 @@
* [Loss Functions](machine_learning/loss_functions.py)
* Lstm
* [Lstm Prediction](machine_learning/lstm/lstm_prediction.py)
* [Mean Shift](machine_learning/mean_shift.py)
* [Mfcc](machine_learning/mfcc.py)
* [Mini Batch Gradient Descent](machine_learning/mini_batch_gradient_descent.py)
* [Multilayer Perceptron Classifier](machine_learning/multilayer_perceptron_classifier.py)
* [Naive Bayes Text Classification](machine_learning/naive_bayes_text_classification.py)
* [Ordinary Least Squares Regression](machine_learning/ordinary_least_squares_regression.py)
* [Polynomial Regression](machine_learning/polynomial_regression.py)
* [Principle Component Analysis](machine_learning/principle_component_analysis.py)
* [Q Learning](machine_learning/q_learning.py)
* [Random Forest Classifier](machine_learning/random_forest_classifier.py)
* [Random Forest Regressor](machine_learning/random_forest_regressor.py)
* [Rmsprop](machine_learning/rmsprop.py)
* [Scoring Functions](machine_learning/scoring_functions.py)
* [Self Organizing Map](machine_learning/self_organizing_map.py)
* [Sequential Minimum Optimization](machine_learning/sequential_minimum_optimization.py)
Expand All @@ -737,6 +752,7 @@
* [Arc Length](maths/arc_length.py)
* [Area](maths/area.py)
* [Area Under Curve](maths/area_under_curve.py)
* [Autocorrelation](maths/autocorrelation.py)
* [Average Absolute Deviation](maths/average_absolute_deviation.py)
* [Average Mean](maths/average_mean.py)
* [Average Median](maths/average_median.py)
Expand Down Expand Up @@ -782,6 +798,7 @@
* [Fibonacci](maths/fibonacci.py)
* [Find Max](maths/find_max.py)
* [Find Min](maths/find_min.py)
* [First Fundamental Form](maths/first_fundamental_form.py)
* [Floor](maths/floor.py)
* [Gamma](maths/gamma.py)
* [Gaussian](maths/gaussian.py)
Expand Down Expand Up @@ -844,6 +861,7 @@
* [Square Root](maths/numerical_analysis/square_root.py)
* [Weierstrass Method](maths/numerical_analysis/weierstrass_method.py)
* [Odd Sieve](maths/odd_sieve.py)
* [Padovan Sequence](maths/padovan_sequence.py)
* [Pell Number](maths/pell_number.py)
* [Perfect Cube](maths/perfect_cube.py)
* [Perfect Number](maths/perfect_number.py)
Expand Down Expand Up @@ -873,6 +891,8 @@
* [Reverse Factorial Recursive](maths/reverse_factorial_recursive.py)
* [Segmented Sieve](maths/segmented_sieve.py)
* Series
* [Alternate Harmonic Series](maths/series/alternate_harmonic_series.py)
* [Alternating Harmonic Series](maths/series/alternating_harmonic_series.py)
* [Arithmetic](maths/series/arithmetic.py)
* [Geometric](maths/series/geometric.py)
* [Geometric Series](maths/series/geometric_series.py)
Expand Down Expand Up @@ -912,6 +932,7 @@
* [Polygonal Numbers](maths/special_numbers/polygonal_numbers.py)
* [Pronic Number](maths/special_numbers/pronic_number.py)
* [Proth Number](maths/special_numbers/proth_number.py)
* [Spy Number](maths/special_numbers/spy_number.py)
* [Triangular Numbers](maths/special_numbers/triangular_numbers.py)
* [Trimorphic Number](maths/special_numbers/trimorphic_number.py)
* [Ugly Numbers](maths/special_numbers/ugly_numbers.py)
Expand Down
254 changes: 254 additions & 0 deletions bit_manipulation/multibit_manipulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
"""Bit integer manipulation, both single bit and multi-bit list-like

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error occurred while parsing the file: bit_manipulation/multibit_manipulation.py

Traceback (most recent call last):
  File "/opt/render/project/src/algorithms_keeper/parser/python_parser.py", line 146, in parse
    reports = lint_file(
              ^^^^^^^^^^
libcst._exceptions.ParserSyntaxError: Syntax Error @ 1:1.
tokenizer error: inconsistent mixing of tabs and spaces

"""Bit integer manipulation, both single bit and multi-bit list-like
^

slicing functions ( get, set, insert, remove ) implemented with
builtin bitwise operations.

See:
https://high-python-ext-3-algorithms.readthedocs.io/ko/latest/chapter5.html#insert-bit
https://en.wikipedia.org/wiki/Bit_manipulation#Bit_manipulation_operations
https://github.com/billbreit/BitWiseApps

All parameters must be must be int >= 0, referred to as a 'bit integer'.

bint:int
The bit integer to be accessed or returned as modified.

index:int
The offset into the bit position from right,
0b010111 -> list [1,1,1,0,1,0]. big-endian -> little-endian
For inserts, index is the position to the right of index,
index 0 -> right of rightmost bit.
For gets, sets and removes, it is the position of the bit itself.

value:int
Either [0,1] for single bit, or int value for multibit,
bit_length(value) <= bitlen.

bitlen:int
The effective mask length, spec. leading zeros
( bitlen 4 value 1 -> 0001 )

The bitwise expressions may look convoluted, but basically, there are
just three parts: left-hand side, value, right-hand side.

For example, say you want to insert two ones in the middle of 0b101101,
that is -> 0b10111101. Index is 3 ( 0 ,1, 2, 3 from the right ) and the
value is 3 (0b11) with a bit length of 2.

- Shift >> index right to produce 0b101
- Shift left << bit length to produce 0b10100.
- OR in the ones producing 0b10111.
- Left shift << index producing 0b10111000.
- Using a bit mask (1 << index)-1 -> 0b111, AND with the original bint,
( 0b101101 & 0b111 ) -> 0b101.
- OR that into the working 0b10111000, that is, ( 0b10111000 | 0b101 )
-> 0b10111101.

To remove the center two bits of 0b101101 -> 0b1001, the process is mostly
the same. Index is 2 for the remove operation on the right-center bit
rather than 3 for inserting, because we are referring to the bit itself
rather the position to the right of the bit index.

- The initial right shift is index (2 ) + bit_length(2), taking out the two
middle bits and producing 0b10.
- The left shift of index produces 0b1000.
- The original bint is ANDed with bitmask 0b11 producing 0b01 which is
ORed with 0b1000 yielding the target 0b1001.

Bit manipulation operations can be tricky to debug. In the insert example
above, the result of inserting 0b11 in the center ( index=3 ) or to the
right ( index=2 ) produces the same correct result despite the unintended
misspecification. Why is it working sometimes and not others ? Frequently,
it's the result of inserting at the wrong index, for the hundredth time !

Various bit insert/remove solutions exist using bin() string functions
and slicing, but this bitwise implementation is significantly faster
(about 3x) on Python for big ints (2^100).

See https://github.com/billbreit/BitWiseApps/blob/main/dev/time_ops.py

"""

bit_length = int.bit_length


def bit_get(bint: int, index: int) -> int:
"""Get value of bit at index in bint.

>>> bit_get(15, 0)
1
>>> bit_get(15, 4)
0
>>> bit_get(0, 4)
0
>>> bit_get(-1, 2)
Traceback (most recent call last):
...
ValueError: All input values must be positive integers.
>>> bit_get(0, -1)
Traceback (most recent call last):
...
ValueError: All input values must be positive integers.
"""

return multibit_get(bint, index, 1)


def bit_set(bint: int, index: int, value: int = 1) -> int:
"""Set bit at index to value 1 or 0, like set() or unset().

>>> bit_set(15, 0, 0)
14
>>> bit_set(15, 4, 1)
31
>>> bit_set(31, 6, 0)
31
>>> bit_set(31, 6, 3)
Traceback (most recent call last):
...
ValueError: Input value must be 1 or 0.
"""

if value not in [0, 1]:
raise ValueError("Input value must be 1 or 0.")

return multibit_set(bint, index, 1, value)


def bit_insert(bint: int, index: int, value: int = 1) -> int:
"""Insert bit value before index.

>>> bit_insert(15, 0, 0)
30
>>> bit_insert(15, 0, 1)
31
>>> bit_insert(15, 4, 1)
31
>>> bit_insert(31, 6, 0)
31
"""

if value not in [0, 1]:
raise ValueError("Input value must be 1 or 0.")

return multibit_insert(bint, index, 1, value)


def bit_remove(bint: int, index: int) -> int:
"""Remove the bit at index from bint.

>>> bit_remove(15, 0)
7
>>> bit_remove(15, 1)
7
>>> bit_remove(31, 4)
15
>>> bit_remove(31, 6)
31
"""

return multibit_remove(bint, index, 1)


def multibit_get(bint: int, index: int, bit_len: int) -> int:
"""Get bit_len number of bits starting from index.
819 = 1100110011.

>>> multibit_get(0, 1, 1)
0
>>> multibit_get(15, 0, 3)
7
>>> multibit_get(819, 2, 4)
12
>>> multibit_get(819, 4, 6)
51
"""

if bint < 0 or index < 0 or bit_len < 0:
raise ValueError("All input values must be positive integers.")

return (bint >> index) & ((1 << bit_len) - 1)


def multibit_set(bint: int, index: int, bit_len: int, value: int) -> int:
"""Overlay bint at index with value for bit_len bits.

>>> multibit_set(0, 1, 1, 0)
0
>>> multibit_set(15, 0, 2, 0)
12
>>> multibit_set(22, 0, 1, 1)
23
>>> multibit_set(22, 2, 1, 0)
18
>>> multibit_set(22, 2, 1, 3)
Traceback (most recent call last):
...
ValueError: Bit length of value can not be greater than specified bit length.
"""

if bint < 0 or index < 0 or bit_len < 0 or value < 0:
raise ValueError("All input values must be positive integers.")
if bit_length(value) > bit_len:
raise ValueError(
"Bit length of value can not be greater than specified bit length."
)

return ((((bint >> (index + bit_len)) << bit_len) | value) << index) | (
bint & (1 << index) - 1
)


def multibit_insert(bint: int, index: int, bit_len: int, value: int) -> int:
"""Insert value before index-th slot

>>> multibit_insert(0, 1, 1, 1)
2
>>> multibit_insert(15, 1, 2, 0)
57
>>> multibit_insert(22, 0, 1, 1)
45
>>> multibit_insert(22, 2, 1, 0)
42
>>> multibit_insert(22, 2, 0, 0)
22
>>> multibit_insert(22, 2, 1, 3)
Traceback (most recent call last):
...
ValueError: Bit length of value can not be greater than specified bit length.
"""

if bint < 0 or index < 0 or bit_len < 0 or value < 0:
raise ValueError("All input values must be positive integers.")
if bit_length(value) > bit_len:
raise ValueError(
"Bit length of value can not be greater than specified bit length."
)

return ((((bint >> index) << bit_len) | value) << index) | bint & ((1 << index) - 1)


def multibit_remove(bint: int, index: int, bit_len: int) -> int:
"""Remove bits in bint from index to index+bit_len.

>>> multibit_remove(3, 1, 1)
1
>>> multibit_remove(15, 1, 2)
3
>>> multibit_remove(22, 0, 1)
11
>>> multibit_remove(22, 2, 2)
6
>>> multibit_remove(22, 2, 6)
2
"""

if bint < 0 or index < 0 or bit_len < 0:
raise ValueError("All input values must be positive integers.")

return ((bint >> index + bit_len) << index) | bint & ((1 << index) - 1)


if __name__ == "__main__":
import doctest

doctest.testmod()