Cidr4 merge algorithm #5

Merged
PavelPatsey merged 91 commits from CIDR4_merge_algorithm into main 2025-01-27 22:05:39 +03:00
Showing only changes of commit 604861aa80 - Show all commits
+34 -25
View File
@@ -1,6 +1,8 @@
from copy import deepcopy
Fedor-Lyanguzov commented 2025-01-07 17:54:03 +03:00 (Migrated from github.com)
Review

Здесь за один проход объединяются все возможные объединения, таким образом мы можем промахнуться мимо цели в M элементов списка.

Здесь за один проход объединяются все возможные объединения, таким образом мы можем промахнуться мимо цели в `M` элементов списка.
Fedor-Lyanguzov commented 2025-01-07 17:55:32 +03:00 (Migrated from github.com)
Review

Здесь не хватает возвращения количества адресов, "попавших под раздачу": не принадлежащих начальному списку, но попавших в результат из-за объединения. Это количество позволит найти оптимальное решение.

Здесь не хватает возвращения количества адресов, "попавших под раздачу": не принадлежащих начальному списку, но попавших в результат из-за объединения. Это количество позволит найти оптимальное решение.
Fedor-Lyanguzov commented 2025-01-07 17:57:45 +03:00 (Migrated from github.com)
Review

Я думаю, использование внешней библиотеки (и вообще любой библиотеки) размывает смысл алгоритма: хотя из следующих строк понятно, что будет сделано; однако не очевидно, как это будет сделано, и будет ли оптимальный ответ, и будет ли оптимальное решение (что не обязательно).

Я думаю, использование внешней библиотеки (и вообще любой библиотеки) размывает смысл алгоритма: хотя из следующих строк понятно, что будет сделано; однако не очевидно, как это будет сделано, и будет ли оптимальный ответ, и будет ли оптимальное решение (что не обязательно).
Fedor-Lyanguzov commented 2025-01-12 17:46:01 +03:00 (Migrated from github.com)
Review

Мне кажется, что функция merge_nodes содержит не все свои обязанности, некоторые из них похоже вложись в функцию reduce_nodes. Стоит их переместить.

Мне кажется, что функция `merge_nodes` содержит не все свои обязанности, некоторые из них похоже вложись в функцию `reduce_nodes`. Стоит их переместить.
Fedor-Lyanguzov commented 2025-01-12 19:00:28 +03:00 (Migrated from github.com)
Review

Алгоритм слишком много делает каждый шаг, из-за этого работает медленно. Как мне кажется, для оптимизации стоит разработать алгоритм начиная с рекурсии, возможно их будет штук 5 связанных, зато это позволит определить характеристики отдельных кусков и принять решение по оптимизации.

Алгоритм слишком много делает каждый шаг, из-за этого работает медленно. Как мне кажется, для оптимизации стоит разработать алгоритм начиная с рекурсии, возможно их будет штук 5 связанных, зато это позволит определить характеристики отдельных кусков и принять решение по оптимизации.
Fedor-Lyanguzov commented 2025-01-12 19:01:34 +03:00 (Migrated from github.com)
Review

Пора перенести тесты в отдельный файл?

Пора перенести тесты в отдельный файл?
from ipaddress import IPv4Address
from typing import List, Tuple
from itertools import groupby
from collections import defaultdict
def get_data(input_file):
@@ -15,43 +17,45 @@ def cidr4_to_binary(cidr4: str) -> str:
ipv4 = IPv4Address(ip_str)
binary_ip = bin(int(ipv4))[2:]
binary_ip = binary_ip.zfill(32)
binary = binary_ip[:vlsm]
binary = binary_ip[:vlsm] + "0" * (32 - vlsm)
return binary
def binary_to_cidr4(binary: str) -> str:
vlsm = len(binary)
binary_ip = binary + "0" * (32 - vlsm)
int_ip = int(binary_ip, 2)
vlsm = binary.rfind("1") + 1 if "1" in binary else 0
int_ip = int(binary, 2)
ip = IPv4Address(int_ip)
return f"{ip}/{vlsm}"
def reduce_binary(binary: str) -> str:
if len(binary) == 0:
return ""
new_binary = binary[:-1]
if "1" not in new_binary:
return ""
return new_binary
assert len(binary) == 32
vlsm = binary.rfind("1")
if vlsm == -1:
return binary
return binary[:vlsm] + "0" + binary[vlsm + 1 :]
def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
ips = set(deepcopy(binaries))
non_reducible_ips = set()
reduction_limit_reached = False
max_vlsm = float("inf")
while (
len(ips) > 0
and len(ips) + len(non_reducible_ips) > req_len
and not reduction_limit_reached
and max_vlsm != -1
):
max_vlsm = len(max(ips, key=lambda x: len(x)))
ip_with_max_vlsm = max(ips, key=lambda x: x.rfind("1"))
max_vlsm = ip_with_max_vlsm.rfind("1")
print(f"{max_vlsm=}")
reduced_ips = set()
merged_ips = set()
for ip in ips:
if len(ip) == max_vlsm:
if ip.rfind("1") == max_vlsm:
reduced_ip = reduce_binary(ip)
if len(reduced_ip) > 0:
if "1" in reduced_ip:
reduced_ips.add(reduced_ip)
else:
non_reducible_ips.add(ip)
@@ -62,6 +66,7 @@ def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
ips = merged_ips
else:
reduction_limit_reached = True
print(f"{len(ips)=}")
ips.update(non_reducible_ips)
return sorted(ips)
@@ -73,6 +78,7 @@ def main():
data = get_data(file)
bin_ips = list(map(cidr4_to_binary, data))
rough_merged_bin_ips = rough_merge_binaries(bin_ips, required_len)
print(f"{len(rough_merged_bin_ips)=}")
for ip in rough_merged_bin_ips:
@@ -80,19 +86,22 @@ def main():
if __name__ == "__main__":
assert cidr4_to_binary("4.78.139.0/24") == "000001000100111010001011"
assert cidr4_to_binary("128.0.0.0/1") == "1"
assert cidr4_to_binary("0.0.0.0/0") == ""
assert cidr4_to_binary("4.78.139.0/24") == "00000100010011101000101100000000"
assert cidr4_to_binary("128.0.0.0/1") == "10000000000000000000000000000000"
assert cidr4_to_binary("0.0.0.0/0") == "0" * 32
assert cidr4_to_binary("0.8.0.0/13") == "00000000000010000000000000000000"
assert binary_to_cidr4("000001000100111010001011") == "4.78.139.0/24"
assert binary_to_cidr4("1") == "128.0.0.0/1"
assert binary_to_cidr4("") == "0.0.0.0/0"
assert binary_to_cidr4("00000100010011101000101100000000") == "4.78.139.0/24"
assert binary_to_cidr4("10000000000000000000000000000000") == "128.0.0.0/1"
assert binary_to_cidr4("00000000000000000000000000000000") == "0.0.0.0/0"
assert binary_to_cidr4("00000000000010000000000000000000") == "0.8.0.0/13"
assert reduce_binary("000001000100111010001011") == "00000100010011101000101"
assert reduce_binary("1") == ""
assert reduce_binary("0") == ""
assert reduce_binary("") == ""
assert reduce_binary("0001") == ""
assert reduce_binary("0000") == ""
assert (
reduce_binary("00000100010011101000101100000000")
== "00000100010011101000101000000000"
)
assert reduce_binary("10000000000000000000000000000000") == "0" * 32
assert reduce_binary("0" * 32) == "0" * 32
assert reduce_binary("00000000000010000000000000000000") == "0" * 32
main()